mirror of https://github.com/Chizi123/.emacs.d.git

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