├── README.org └── github-search.el /README.org: -------------------------------------------------------------------------------- 1 | [[http://melpa.org/#/github-search][file:http://melpa.org/packages/github-search-badge.svg]] 2 | [[https://stable.melpa.org/#/github-search][file:https://stable.melpa.org/packages/github-search-badge.svg]] 3 | * Installation 4 | 5 | Install from MELPA with ~M-x package-install github-search~. See the [[https://github.com/milkypostman/melpa][melpa repository]] for details about how to set up MELPA if you have not already done so. 6 | * Usage 7 | Run the command ~github-search-clone-repo~ and select a repository and a location to which to clone said repository. 8 | * Configuration 9 | ** Author's configuration 10 | Check out the [[https://github.com/IvanMalison/dotfiles/blob/master/dotfiles/emacs.d/README.org#github-search][author's configuration]] for some ideas. 11 | -------------------------------------------------------------------------------- /github-search.el: -------------------------------------------------------------------------------- 1 | ;;; github-search.el --- Clone repositories by searching github 2 | 3 | ;; Copyright (C) 2016 Ivan Malison 4 | 5 | ;; Author: Ivan Malison 6 | ;; Keywords: github search clone api gh magit vc tools 7 | ;; URL: https://github.com/IvanMalison/github-search 8 | ;; Version: 0.0.1 9 | ;; Package-Requires: ((magit "0.8.1") (gh "1.0.0")) 10 | 11 | ;; This program is free software; you can redistribute it and/or modify 12 | ;; it under the terms of the GNU General Public License as published by 13 | ;; the Free Software Foundation, either version 3 of the License, or 14 | ;; (at your option) any later version. 15 | 16 | ;; This program is distributed in the hope that it will be useful, 17 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 | ;; GNU General Public License for more details. 20 | 21 | ;; You should have received a copy of the GNU General Public License 22 | ;; along with this program. If not, see . 23 | 24 | ;;; Commentary: 25 | 26 | ;; This package provides functions to clone github repositories that 27 | ;; are selected from queries to the github search api. 28 | 29 | ;;; Code: 30 | (require 'gh-search) 31 | (require 'magit-remote) 32 | (require 'cl-lib) 33 | 34 | (defvar github-search-repo-format-function 'github-search-string-for-repo) 35 | (defvar github-search-user-format-function 'github-search-string-for-user) 36 | (defvar github-search-get-clone-url-function 'github-search-get-clone-url) 37 | (defvar github-search-get-target-directory-for-repo-function 38 | 'github-search-prompt-for-target-directory) 39 | (defvar github-search-clone-repository-function 40 | 'github-search-default-clone-repository-function) 41 | (defvar github-search-page-limit 1) 42 | 43 | (defun github-search-default-clone-repository-function (repo directory) 44 | (magit-clone-regular repo directory nil)) 45 | 46 | (defun github-search-format-repository (repo) 47 | (cons (funcall github-search-repo-format-function repo) repo)) 48 | 49 | (defun github-search-format-user (user) 50 | (cons (funcall github-search-user-format-function user) user)) 51 | 52 | (defun github-search-for-completion (search-string &optional page-limit) 53 | (let* ((search-api (make-instance gh-search-api)) 54 | (search-response (gh-search-repos search-api search-string page-limit)) 55 | (repos (oref search-response :data))) 56 | (mapcar 'github-search-format-repository repos))) 57 | 58 | (defun github-search-users-for-completion (search-string &optional page-limit) 59 | (let* ((search-api (make-instance gh-search-api)) 60 | (search-response (gh-search-users search-api search-string page-limit)) 61 | (users (oref search-response :data))) 62 | (mapcar 'github-search-format-user users))) 63 | 64 | (defun github-search-get-repos-from-user-for-completion (user) 65 | (let* ((repo-api (make-instance gh-repos-api)) 66 | (repo-response (gh-repos-user-list repo-api (oref user :login))) 67 | (repos (oref repo-response :data))) 68 | (mapcar 'github-search-format-repository repos))) 69 | 70 | (defun github-search-string-for-repo (repository) 71 | (let ((owner (oref repository :owner))) 72 | (format "%s/%s" 73 | (if owner (oref owner :login) "owner-not-found") 74 | (oref repository :name)))) 75 | 76 | (defun github-search-string-for-user (user) 77 | (oref user :login)) 78 | 79 | (defun github-search-get-clone-url (repository) 80 | (oref repo :ssh-url)) 81 | 82 | (defun github-search-select-user-from-search-string (search-string) 83 | (github-search-select-candidate "Select a user: " 84 | (github-search-users-for-completion search-string github-search-page-limit))) 85 | 86 | (defun github-search-select-candidate (prompt candidates) 87 | (let ((selection (completing-read prompt candidates))) 88 | (cdr (assoc selection candidates)))) 89 | 90 | (defun github-search-prompt-for-target-directory (repo) 91 | (let* ((remote-url (funcall github-search-get-clone-url-function repo)) 92 | (input-target (read-directory-name 93 | "Clone to: " nil nil nil 94 | (and (string-match "\\([^./]+\\)\\(\\.git\\)?$" remote-url) 95 | (match-string 1 remote-url))))) 96 | (if (file-exists-p input-target) (concat input-target (oref repo :name)) 97 | input-target))) 98 | 99 | (defun github-search-get-target-directory-for-repo (repo) 100 | (funcall github-search-get-target-directory-for-repo-function repo)) 101 | 102 | (defun github-search-select-and-clone-repo-from-repos (repos-for-completion) 103 | (github-search-do-repo-clone 104 | (github-search-select-candidate "Select a repo: " repos-for-completion))) 105 | 106 | (defun github-search-do-repo-clone (repo) 107 | (let ((remote-url (funcall github-search-get-clone-url-function repo)) 108 | (target-directory (github-search-get-target-directory-for-repo repo))) 109 | (funcall github-search-clone-repository-function remote-url target-directory))) 110 | 111 | ;;;###autoload 112 | (defun github-search-user-clone-repo (search-string) 113 | "Query github using SEARCH-STRING and clone the selected repository." 114 | (interactive 115 | (list (read-from-minibuffer "Enter a github user search string: "))) 116 | (let* ((user (github-search-select-user-from-search-string search-string)) 117 | (user-repos (github-search-get-repos-from-user-for-completion user))) 118 | (github-search-select-and-clone-repo-from-repos user-repos))) 119 | 120 | ;;;###autoload 121 | (defun github-search-clone-repo (search-string) 122 | "Query github using SEARCH-STRING and clone the selected repository." 123 | (interactive 124 | (list (read-from-minibuffer "Enter a github search string: "))) 125 | (let* ((repos (github-search-for-completion search-string 126 | github-search-page-limit))) 127 | (github-search-select-and-clone-repo-from-repos repos))) 128 | 129 | (provide 'github-search) 130 | ;;; github-search.el ends here 131 | --------------------------------------------------------------------------------