Skip to content

Instantly share code, notes, and snippets.

@hex2010
Created October 6, 2016 11:51
Show Gist options
  • Save hex2010/51b76375f8f645aaceb8b4dd9afade45 to your computer and use it in GitHub Desktop.
Save hex2010/51b76375f8f645aaceb8b4dd9afade45 to your computer and use it in GitHub Desktop.
Open file/project/workspace/products with Xcode from within Emacs
;;; hx-xcode --- Utils work with Xcode.
;;; Commentary:
;; This is free and unencumbered software released into the public domain.
;; Anyone is free to copy, modify, publish, use, compile, sell, or
;; distribute this software, either in source code form or as a compiled
;; binary, for any purpose, commercial or non-commercial, and by any
;; means.
;; In jurisdictions that recognize copyright laws, the author or authors
;; of this software dedicate any and all copyright interest in the
;; software to the public domain. We make this dedication for the benefit
;; of the public at large and to the detriment of our heirs and
;; successors. We intend this dedication to be an overt act of
;; relinquishment in perpetuity of all present and future rights to this
;; software under copyright law.
;; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
;; EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
;; MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
;; IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
;; OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
;; ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
;; OTHER DEALINGS IN THE SOFTWARE.
;; For more information, please refer to <http://unlicense.org/>
;;; Code:
(require 'cl-lib)
(require 'ivy)
(defcustom hx-xcode-launch-product-cmd "open \"%s\""
"Shell command to launch product app."
:type 'string
:options '(turn-on-auto-fill)
:group 'hx-xcode)
(defcustom hx-xcode-derived-dir "~/Library/Developer/Xcode/DerivedData"
"DerivedData directory to find products, this variable should should not contains whitespaces."
:type 'string
:options '(turn-on-auto-fill)
:group 'hx-xcode)
(defvar hx-xcode-launch-product-history nil
"History list for hx-xcode-launch-product.")
(defun hx-xcode--list ()
(split-string (shell-command-to-string (concat "find " hx-xcode-derived-dir
" -name \"*.app\"")) "\n" t))
(defun hx-xcode--list-shorthand ()
(let ((pl (hx-xcode--list))
(ret '()))
(dolist (x pl ret)
(and (string-match (concat ".*/\\([^\\-]+\\).*/Build/Products/\\(Debug\\|Release\\)/\\(.+app\\)") x)
(setq ret (append ret (list (concat (match-string 3 x) "|" (match-string 2 x) "|"
(match-string 1 x) ))))))))
(defun hx-xcode--launch-product-shorthand (k)
(let ((v (split-string k "|"))
(r nil))
(setq r (concat "/" (nth 2 v) ".*/Build/Products/" (nth 1 v) "/" (nth 0
v)))
(dolist (x (hx-xcode--list))
(if (string-match-p r x)
(shell-command (format hx-xcode-launch-product-cmd x))))))
;;;###autoload
(defun hx-xcode-launch-product ()
"Launch xcode products."
(interactive)
(ivy-read "Launch Product: " (hx-xcode--list-shorthand)
:action (lambda (x)
(with-ivy-window (hx-xcode--launch-product-shorthand x)))
:require-match t
:caller 'hx-xcode-launch-product
:history 'hx-xcode-launch-product-history
:preselect (nth 0 hx-xcode-launch-product-history)))
(defun hx-xcode--find-in (dir ext)
(let ((ret (car (cl-member-if (lambda (x)
(equal ext (file-name-extension x)))
(directory-files dir)))))
(and ret (concat dir "/" ret))))
(defun hx-xcode--locate-project-in (dir)
(if (not (equal "/" dir))
(or (hx-xcode--find-in dir "xcodeproj")
(hx-xcode--locate-project-in (file-name-directory (directory-file-name dir))))))
(defun hx-xcode-locate-project (&optional tryws)
"Locate dominating xcode project, optional locate workspace if project not found."
(or (hx-xcode--locate-project-in (expand-file-name (directory-file-name default-directory)))
(and tryws (hx-xcode-locate-workspace))))
(defun hx-xcode--locate-workspace-in (dir)
(if (not (equal "/" dir))
(or (hx-xcode--find-in dir "xcworkspace")
(hx-xcode--locate-workspace-in (file-name-directory (directory-file-name dir))))))
(defun hx-xcode-locate-workspace ()
"Locate dominating xcode workspace."
(hx-xcode--locate-workspace-in (expand-file-name (directory-file-name default-directory))))
;;;###autoload
(defun hx-xcode-open-project (&optional tryws)
"Open dominating project in Xcode, optional open workspace if project not found."
(interactive)
(let ((x (hx-xcode-locate-project tryws)))
(if x (hx-xcode-open x)
(message (concat "*.xcodeproj not found for " default-directory)))))
;;;###autoload
(defun hx-xcode-open-workspace ()
"Open dominating workspace in Xcode."
(interactive)
(let ((x (hx-xcode-locate-workspace)))
(if x (hx-xcode-open x)
(message (concat "*.xcworkspace not found for " default-directory)))))
;;;###autoload
(defun hx-xcode-open-project-or-workspace ()
"Open dominating project or workspace in Xcode."
(interactive)
(hx-xcode-open-project t))
(defun hx-xcode--files-to-args (files)
(if (listp files)
(let (ret)
(dolist (f files ret)
(setq ret (or (and f (concat ret " \"" f "\""))
ret))))
(and files (concat "\"" files "\""))))
(defun hx-xcode-open (files)
"Open single file or list of file with Xcode"
(let ((args (hx-xcode--files-to-args files)))
(and args
(async-shell-command (concat "open -a Xcode " args)))))
;;;###autoload
(defun hx-xcode-open-buffer-file (&optional prjws)
"Open buffer file in Xcode, optional open with dominating project or workspace."
(interactive)
(let ((files (list (buffer-file-name (current-buffer)))))
(if prjws (setq files (cons (hx-xcode-locate-project t) files)))
(or (hx-xcode-open files)
(message "Failed to open %s with Xcode." files))))
;;;###autoload
(defun hx-xcode-open-buffer-file-ex ()
"Open buffer file with dominating project or workspace in Xcode."
(interactive)
(hx-xcode-open-buffer-file t))
(provide 'hx-xcode)
;;; hx-xcode.el ends here
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment