Klimi's new dotfiles with stow.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

213 lines
9.1 KiB

4 years ago
  1. ;;; helm-external.el --- Run Externals commands within Emacs with helm completion. -*- lexical-binding: t -*-
  2. ;; Copyright (C) 2012 ~ 2019 Thierry Volpiatto <thierry.volpiatto@gmail.com>
  3. ;; This program is free software; you can redistribute it and/or modify
  4. ;; it under the terms of the GNU General Public License as published by
  5. ;; the Free Software Foundation, either version 3 of the License, or
  6. ;; (at your option) any later version.
  7. ;; This program is distributed in the hope that it will be useful,
  8. ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. ;; GNU General Public License for more details.
  11. ;; You should have received a copy of the GNU General Public License
  12. ;; along with this program. If not, see <http://www.gnu.org/licenses/>.
  13. ;;; Code:
  14. (require 'cl-lib)
  15. (require 'helm)
  16. (require 'helm-help)
  17. (require 'helm-net)
  18. (defgroup helm-external nil
  19. "External related Applications and libraries for Helm."
  20. :group 'helm)
  21. (defcustom helm-raise-command nil
  22. "A shell command to jump to a window running specific program.
  23. Need external program wmctrl.
  24. This will be use with `format', so use something like \"wmctrl -xa %s\"."
  25. :type 'string
  26. :group 'helm-external)
  27. (defcustom helm-external-programs-associations nil
  28. "Alist to store externals programs associated with file extension.
  29. This variable overhide setting in .mailcap file.
  30. e.g : '\(\(\"jpg\" . \"gqview\"\) (\"pdf\" . \"xpdf\"\)\) "
  31. :type '(alist :key-type string :value-type string)
  32. :group 'helm-external)
  33. (defcustom helm-default-external-file-browser "nautilus"
  34. "Default external file browser for your system.
  35. Directories will be opened externally with it when
  36. opening file externally in `helm-find-files'.
  37. Set to nil if you do not have external file browser
  38. or do not want to use it.
  39. Windows users should set that to \"explorer.exe\"."
  40. :group 'helm-external
  41. :type 'string)
  42. ;;; Internals
  43. (defvar helm-external-command-history nil)
  44. (defvar helm-external-commands-list nil
  45. "A list of all external commands the user can execute.
  46. If this variable is not set by the user, it will be calculated
  47. automatically.")
  48. (defun helm-external-commands-list-1 (&optional sort)
  49. "Returns a list of all external commands the user can execute.
  50. If `helm-external-commands-list' is non-nil it will
  51. return its contents. Else it calculates all external commands
  52. and sets `helm-external-commands-list'."
  53. (helm-aif helm-external-commands-list
  54. it
  55. (setq helm-external-commands-list
  56. (cl-loop
  57. for dir in (split-string (getenv "PATH") path-separator)
  58. when (and (file-exists-p dir) (file-accessible-directory-p dir))
  59. for lsdir = (cl-loop for i in (directory-files dir t)
  60. for bn = (file-name-nondirectory i)
  61. when (and (not (member bn completions))
  62. (not (file-directory-p i))
  63. (file-executable-p i))
  64. collect bn)
  65. append lsdir into completions
  66. finally return
  67. (if sort (sort completions 'string-lessp) completions)))))
  68. (defun helm-run-or-raise (exe &optional file)
  69. "Run asynchronously EXE or jump to the application window.
  70. If EXE is already running just jump to his window if `helm-raise-command'
  71. is non--nil.
  72. When FILE argument is provided run EXE with FILE."
  73. (let* ((real-com (car (split-string exe)))
  74. (proc (if file (concat real-com " " file) real-com))
  75. process-connection-type)
  76. (if (get-process proc)
  77. (if helm-raise-command
  78. (shell-command (format helm-raise-command real-com))
  79. (error "Error: %s is already running" real-com))
  80. (when (member real-com helm-external-commands-list)
  81. (message "Starting %s..." real-com)
  82. (if file
  83. (start-process-shell-command
  84. proc nil (format "%s %s"
  85. real-com
  86. (shell-quote-argument
  87. (if (eq system-type 'windows-nt)
  88. (helm-w32-prepare-filename file)
  89. (expand-file-name file)))))
  90. (start-process-shell-command proc nil real-com))
  91. (set-process-sentinel
  92. (get-process proc)
  93. (lambda (process event)
  94. (when (and (string= event "finished\n")
  95. helm-raise-command
  96. (not (helm-get-pid-from-process-name real-com)))
  97. (shell-command (format helm-raise-command "emacs")))
  98. (message "%s process...Finished." process))))
  99. (setq helm-external-commands-list
  100. (cons real-com
  101. (delete real-com helm-external-commands-list))))))
  102. (defun helm-get-mailcap-for-file (filename)
  103. "Get the command to use for FILENAME from mailcap files."
  104. (mailcap-parse-mailcaps)
  105. (let* ((ext (file-name-extension filename))
  106. (mime (when ext (mailcap-extension-to-mime ext)))
  107. (result (when mime (mailcap-mime-info mime))))
  108. ;; If elisp file have no associations in .mailcap
  109. ;; `mailcap-maybe-eval' is returned, in this case just return nil.
  110. (when (stringp result) (helm-basename result))))
  111. (defun helm-get-default-program-for-file (filename)
  112. "Try to find a default program to open FILENAME.
  113. Try first in `helm-external-programs-associations' and then in mailcap file
  114. if nothing found return nil."
  115. (let* ((ext (file-name-extension filename))
  116. (def-prog (assoc-default ext helm-external-programs-associations)))
  117. (cond ((and def-prog (not (string= def-prog ""))) def-prog)
  118. ((and helm-default-external-file-browser (file-directory-p filename))
  119. helm-default-external-file-browser)
  120. (t (helm-get-mailcap-for-file filename)))))
  121. (defun helm-open-file-externally (file)
  122. "Open FILE with an external program.
  123. Try to guess which program to use with `helm-get-default-program-for-file'.
  124. If not found or a prefix arg is given query the user which tool to use."
  125. (let* ((fname (expand-file-name file))
  126. (collection (helm-external-commands-list-1 'sort))
  127. (def-prog (helm-get-default-program-for-file fname))
  128. (program (if (or helm-current-prefix-arg (not def-prog))
  129. ;; Prefix arg or no default program.
  130. (prog1
  131. (helm-comp-read
  132. "Program: " collection
  133. :must-match t
  134. :name "Open file Externally"
  135. :del-input nil
  136. :history helm-external-command-history)
  137. ;; Always prompt to set this program as default.
  138. (setq def-prog nil))
  139. ;; No prefix arg or default program exists.
  140. def-prog)))
  141. (unless (or def-prog ; Association exists, no need to record it.
  142. ;; Don't try to record non--filenames associations (e.g urls).
  143. (not (file-exists-p fname)))
  144. (when
  145. (y-or-n-p
  146. (format
  147. "Do you want to make `%s' the default program for this kind of files? "
  148. program))
  149. (helm-aif (assoc (file-name-extension fname)
  150. helm-external-programs-associations)
  151. (setq helm-external-programs-associations
  152. (delete it helm-external-programs-associations)))
  153. (push (cons (file-name-extension fname)
  154. (helm-read-string
  155. "Program (Add args maybe and confirm): " program))
  156. helm-external-programs-associations)
  157. (customize-save-variable 'helm-external-programs-associations
  158. helm-external-programs-associations)))
  159. (helm-run-or-raise program file)
  160. (setq helm-external-command-history
  161. (cons program
  162. (delete program
  163. (cl-loop for i in helm-external-command-history
  164. when (executable-find i) collect i))))))
  165. ;;;###autoload
  166. (defun helm-run-external-command (program)
  167. "Preconfigured `helm' to run External PROGRAM asyncronously from Emacs.
  168. If program is already running exit with error.
  169. You can set your own list of commands with
  170. `helm-external-commands-list'."
  171. (interactive (list
  172. (helm-comp-read
  173. "RunProgram: "
  174. (helm-external-commands-list-1 'sort)
  175. :must-match t
  176. :del-input nil
  177. :name "External Commands"
  178. :history helm-external-command-history)))
  179. (helm-run-or-raise program)
  180. (setq helm-external-command-history
  181. (cons program (delete program
  182. (cl-loop for i in helm-external-command-history
  183. when (executable-find i) collect i)))))
  184. (provide 'helm-external)
  185. ;; Local Variables:
  186. ;; byte-compile-warnings: (not obsolete)
  187. ;; coding: utf-8
  188. ;; indent-tabs-mode: nil
  189. ;; End:
  190. ;;; helm-external ends here