Quantcast

shell-command in Windows 7

classic Classic list List threaded Threaded
18 messages Options
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

shell-command in Windows 7

drain
I've been using this code to create functions that open files / folders
within Emacs in Windows 7:

(defun open-buffer-path ()
"Run explorer on the directory of the current buffer."
(interactive)
(shell-command (concat "explorer " (replace-regexp-in-string "/" "\\\\"
(file-name-directory (buffer-file-name)) t t))))

(defun firefox ()
   (interactive)
   (shell-command (concat "explorer " (replace-regexp-in-string "/"
"\\\\" "E:\\Program Files\\Mozilla Firefox\\firefox.exe" t t))))

This worked fine for a while. Then I erased one of my older OSes on a
different partition and created an NTFS partition for extra Windows 7
storage. This did not change the drive number of Windows 7 at all. But
for some reason, after that repartitioning, the above code only works if
I alternative between the two different directory string types. Thus if
I had the above before, on system reboot, I have to replace it all with:

(defun .emacs-open ()
"Run explorer on the directory of the current buffer."
(interactive)
(shell-command (concat "explorer " (replace-regexp-in-string "/" "\\\\"
"E:/Users/John/AppData/Roaming/" t t))))

And vice-versa, otherwise Emacs is unable to open the file / directory I
want, and just opens to the same default directory when I call each
function.  I created a workaround in which I press F12 to alternate
between the two load files (I put these settings in a dedicated .el),
but I'm very curious why this happens, and ideally a workaround like
this would not be necessary.


Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: shell-command in Windows 7

John Mastro
42 147 <[hidden email]> wrote:

> I've been using this code to create functions that open files / folders
> within Emacs in Windows 7:
>
> (defun open-buffer-path ()
> "Run explorer on the directory of the current buffer."
> (interactive)
> (shell-command (concat "explorer " (replace-regexp-in-string "/" "\\\\"
> (file-name-directory (buffer-file-name)) t t))))
>
> (defun firefox ()
>   (interactive)
>   (shell-command (concat "explorer " (replace-regexp-in-string "/" "\\\\"
> "E:\\Program Files\\Mozilla Firefox\\firefox.exe" t t))))
>
> This worked fine for a while. Then I erased one of my older OSes on a
> different partition and created an NTFS partition for extra Windows 7
> storage. This did not change the drive number of Windows 7 at all. But for
> some reason, after that repartitioning, the above code only works if I
> alternative between the two different directory string types. Thus if I had
> the above before, on system reboot, I have to replace it all with:
>
> (defun .emacs-open ()
> "Run explorer on the directory of the current buffer."
> (interactive)
> (shell-command (concat "explorer " (replace-regexp-in-string "/" "\\\\"
> "E:/Users/John/AppData/Roaming/" t t))))
>
> And vice-versa, otherwise Emacs is unable to open the file / directory I
> want, and just opens to the same default directory when I call each
> function.  I created a workaround in which I press F12 to alternate between
> the two load files (I put these settings in a dedicated .el), but I'm very
> curious why this happens, and ideally a workaround like this would not be
> necessary.

I think using (w32-shell-execute "open" ...) is the right way to do this
on Windows. Does the following work for you?

    (defun w32-open-file (file)
      (interactive "fOpen file: ")
      (w32-shell-execute "open" file))

    (defun firefox ()
      (interactive)
      (w32-open-file "e:/Program Files/Mozilla Firefox/firefox.exe"))

    (defun open-buffer-directory (buffer)
      (interactive
       (if current-prefix-arg
           (read-buffer "Open buffer directory: " nil t)
         (list (current-buffer))))
      (with-current-buffer buffer
        (let ((file (buffer-file-name)))
          (if file
              (w32-open-file (file-name-directory file))
            (user-error "Buffer `%s' is not visiting a file" (buffer-name))))))

Hope that helps

        John

Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: shell-command in Windows 7

John Mastro
John Mastro <[hidden email]> wrote:

>     (defun open-buffer-directory (buffer)
>       (interactive
>        (if current-prefix-arg
>            (read-buffer "Open buffer directory: " nil t)
>          (list (current-buffer))))
>       (with-current-buffer buffer
>         (let ((file (buffer-file-name)))
>           (if file
>               (w32-open-file (file-name-directory file))
>             (user-error "Buffer `%s' is not visiting a file" (buffer-name))))))

Oops, bad `interactive' spec. That should be:

    (defun open-buffer-directory (buffer)
      (interactive
       (list (if current-prefix-arg
                 (read-buffer "Open buffer directory: " nil t)
               (current-buffer))))
      (with-current-buffer buffer
        (let ((file (buffer-file-name)))
          (if file
              (w32-open-file (file-name-directory file))
            (user-error "Buffer `%s' is not visiting a file" (buffer-name))))))

Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: shell-command in Windows 7

drain
That's much better! I forgot to mention that even when the earlier code
worked, I always got the follow error:

(Shell command failed with code 1 and no output)

Which slightly annoyed me, even if it was only a side-effect of the
desired functionality.

But now I get what I want minus the error message.

Am 4/14/2017 um 7:13 PM schrieb John Mastro:

> (defun open-buffer-directory (buffer)
>        (interactive
>         (list (if current-prefix-arg
>                   (read-buffer "Open buffer directory: " nil t)
>                 (current-buffer))))
>        (with-current-buffer buffer
>          (let ((file (buffer-file-name)))
>            (if file
>                (w32-open-file (file-name-directory file))
>              (user-error "Buffer `%s' is not visiting a file" (buffer-name))))))


Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: shell-command in Windows 7

drain
In reply to this post by John Mastro
It's also much faster. Zero launch lag.

Is this better because it is based on newer Emacs, or is it just better?
What was wrong with the old code?

Anyway, much thanks.


Am 4/14/2017 um 7:13 PM schrieb John Mastro:

> John Mastro <[hidden email]> wrote:
>>      (defun open-buffer-directory (buffer)
>>        (interactive
>>         (if current-prefix-arg
>>             (read-buffer "Open buffer directory: " nil t)
>>           (list (current-buffer))))
>>        (with-current-buffer buffer
>>          (let ((file (buffer-file-name)))
>>            (if file
>>                (w32-open-file (file-name-directory file))
>>              (user-error "Buffer `%s' is not visiting a file" (buffer-name))))))
> Oops, bad `interactive' spec. That should be:
>
>      (defun open-buffer-directory (buffer)
>        (interactive
>         (list (if current-prefix-arg
>                   (read-buffer "Open buffer directory: " nil t)
>                 (current-buffer))))
>        (with-current-buffer buffer
>          (let ((file (buffer-file-name)))
>            (if file
>                (w32-open-file (file-name-directory file))
>              (user-error "Buffer `%s' is not visiting a file" (buffer-name))))))


Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: shell-command in Windows 7

John Mastro
42 147 <[hidden email]> wrote:
> It's also much faster. Zero launch lag.
>
> Is this better because it is based on newer Emacs, or is it just
> better? What was wrong with the old code?

I don't really know but there's a good chance someone who does will
chime in. I use a Windows desktop at work by necessity, but I basically
install Emacs and Cygwin and then try to pretend it's a Unix :)

As far as I know, `w32-shell-execute' (the Emacs primitive used by the
code I suggested) longstanding. My impression is that it's just not as
widely known as `shell-command', `call-process', etc., because many
(most?) people writing tutorials and such are on some variety of
Unix-like system (mostly GNU/Linux or MacOS).

> Anyway, much thanks.

You're welcome - glad it helped

        John

Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: shell-command in Windows 7

Eli Zaretskii
In reply to this post by drain
> From: 42 147 <[hidden email]>
> Date: Fri, 14 Apr 2017 21:48:10 +0200
>
> It's also much faster. Zero launch lag.

Perhaps because it avoids launching the shell.

> What was wrong with the old code?

I don't think I understood your description of your problem with the
old code to answer that.

Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: shell-command in Windows 7

drain
In reply to this post by John Mastro
Two problems before:

(1) I got the error message

(Shell command failed with code 1 and no output)

Even when the files / programs / directories would open as desired. This
was still undesirable buggy behavior.

(2) Each time I launched Emacs I had to switch to the other directory
string format to get back (1). This made no sense at all. To be specific:

(a) "E:\\Program Files\\Mozilla Firefox\\firefox.exe"

had to be switched to:

(b) "E:/Program Files/Mozilla Firefox/firefox.exe"

in the body of the code I cited in the first e-mail, if (a) was what I
had the previous Emacs launch. And (b) had to be switched back to (a) if
(b) was what I had the previous Emacs launch.

It's also possible the alternating was dependent on a Windows reset. I
had only been launching Emacs once per Windows session.




Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: shell-command in Windows 7

Eli Zaretskii
> From: 42 147 <[hidden email]>
> Date: Sat, 15 Apr 2017 09:40:24 +0200
>
> Two problems before:
>
> (1) I got the error message
>
> (Shell command failed with code 1 and no output)

That's because you are using shell-command to invoke Explorer, which
is a GUI program that continues to run in parallel with Emacs.  You
can ignore the exit status in this case.

> Even when the files / programs / directories would open as desired. This
> was still undesirable buggy behavior.
>
> (2) Each time I launched Emacs I had to switch to the other directory
> string format to get back (1). This made no sense at all. To be specific:
>
> (a) "E:\\Program Files\\Mozilla Firefox\\firefox.exe"
>
> had to be switched to:
>
> (b) "E:/Program Files/Mozilla Firefox/firefox.exe"
>
> in the body of the code I cited in the first e-mail, if (a) was what I
> had the previous Emacs launch. And (b) had to be switched back to (a) if
> (b) was what I had the previous Emacs launch.

That doesn't happen to me in "emacs -Q", so it's most probable some of
your customizations that caused this.  In particular, there's no
"memory" in Emacs of the file names it used in invoking programs.

Btw, please note that what you write above is somewhat inconsistent:

  (defun firefox ()
     (interactive)
     (shell-command (concat "explorer " (replace-regexp-in-string "/"
  "\\\\" "E:\\Program Files\\Mozilla Firefox\\firefox.exe" t t))))

First, I needed to use "\\", not "\\\\" in my testing, otherwise I get
an error.

Second, I'm not sure what you are saying, exactly.  Are you saying
that in one session you needed to use this:

  (defun firefox ()
     (interactive)
     (shell-command (concat "explorer " (replace-regexp-in-string "/"
  "\\" "E:/Program Files/Mozilla Firefox/firefox.exe" t t))))

and in the next you needed to use this:

  (defun firefox ()
     (interactive)
     (shell-command (concat "explorer " (replace-regexp-in-string
  "\\\\" "/" "E:\\Program Files\\Mozilla Firefox\\firefox.exe" t t))))

?  That most probably means either some customization which records
the file name somewhere, or some weird shell tricks you have on your
system.  I cannot reproduce this here.

Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: shell-command in Windows 7

drain
In reply to this post by John Mastro
   Second, I'm not sure what you are saying,
   exactly. Are you saying that in one session
   you needed to use this [...]

Yes, but I had to keep alternating. I could never use the same directory
address style in two consecutive sessions. I had to switch to the
alternative every time (i.e., between the double backslash and the forward
slash versions of the same code).

Session 1: forward slash version works.
Session 2: forward slash version does not work, but double backslash
version does.
Session 3: double backslash version does not work, but forward slash
version does.

Ad infinitum.

That is what made it odd.

I should add that to keep my inits portable I made the following change to
my .emacs:

(setenv "HOME" "g:/windows_home/") ;; folder on usb drive

(load "~/.emacs.d/system-settings.el") ;; contains load files for all inits

The drive letter for the USB had been automatically reassigned after the
recent partition. I changed it back to G: in Windows and everything else
was working fine. The only thing that changed was the functionality of this
code as described.

Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: shell-command in Windows 7

Eli Zaretskii
> From: 42 147 <[hidden email]>
> Date: Sat, 15 Apr 2017 12:06:06 +0200
>
>    Second, I'm not sure what you are saying,
>    exactly. Are you saying that in one session
>    you needed to use this [...]
>
> Yes, but I had to keep alternating. I could never use the same directory
> address style in two consecutive sessions. I had to switch to the
> alternative every time (i.e., between the double backslash and the forward
> slash versions of the same code).

Like I said, the key to this riddle is most probably in your
customizations or in your system configuration.  I certainly don't see
that here, and it doesn't seem to be an Emacs problem.

Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: shell-command in Windows 7

drain
In reply to this post by John Mastro
I narrowed it down to setup-cygwin.el. The only change I made to this file
was to replace every instance of C:/ with E:/ because Windows 7 installed
on the E: drive.

Otherwise, not sure. It might be:

(defcustom cygwin-root-directory (or (setcyg-dir-p "E:/cygwin64/")
(setcyg-dir-p "E:/cygwin/"))
   "Root directory of Cygwin installation.
It should have subdirectories `bin' and `usr/info'.
Subdirectory `bin' should have file `bin/bash.exe'."
   :group 'setup-cygwin :type 'directory)

(unless (setcyg-dir-p cygwin-root-directory)
   (error "Cannot find Cygwin.  Please customize option
`cygwin-root-directory'"))

That is causing problems. If I don't load setup-cygwin.el, I am able to use
the double backslash version of the code every time as before:

  (defun firefox ()
    (interactive)
  (shell-command (concat "explorer " (replace-regexp-in-string "/"
"\\\\" "E:\\Program Files\\Mozilla Firefox\\firefox.exe" t t))))

But curiously the forward slash version does not work every time:

   (defun firefox ()
   "Run explorer on the directory of the current buffer."
   (interactive)
   (shell-command (concat "explorer " (replace-regexp-in-string "/"
"\\\\" "E:/Program Files/Mozilla Firefox/firefox.exe" t t))))

Even if I stop loading setup-cygwin.el.

However, if I replace "\\\\" with "\\" as you did, then both versions work
every time (meaning I never have to alternate), though only if I don't load
setup-cygwin.el. That remains the source of the underlying problem, at
least as I have it configured (although again, I changed nothing in this
file but C:/ to E:/. Everything is in there the way Markus Hoenika and Drew
Adams wrote it).

Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

RE: shell-command in Windows 7

Drew Adams
> setup-cygwin.el. That remains the source of the underlying problem, at
> least as I have it configured (although again, I changed nothing in this
> file but C:/ to E:/. Everything is in there the way Markus Hoenika and
> Drew Adams wrote it).

Sounds like you should just not load setup-cygwin.el and all
will be well.  Sorry for the trouble.

Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: shell-command in Windows 7

drain
setup-cygwin.el is perfectly compatible with the code that John Mastro
suggested (which works better than what I had previously anyway). I need
setup-cygwin.el to run cygwin in Emacs. No way I'll stop loading it!


Am 4/15/2017 um 8:02 PM schrieb Drew Adams:
>> setup-cygwin.el. That remains the source of the underlying problem, at
>> least as I have it configured (although again, I changed nothing in this
>> file but C:/ to E:/. Everything is in there the way Markus Hoenika and
>> Drew Adams wrote it).
> Sounds like you should just not load setup-cygwin.el and all
> will be well.  Sorry for the trouble.


Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: shell-command in Windows 7

John Mastro
42 147 <[hidden email]> wrote:
> setup-cygwin.el is perfectly compatible with the code that John Mastro
> suggested (which works better than what I had previously anyway). I need
> setup-cygwin.el to run cygwin in Emacs. No way I'll stop loading it!

I've been using native Windows builds of Emacs together with Cygwin for
several years now. (Eli recommends against it for very sensible reasons,
but I haven't found anything better and it works well enough for me).

During that time, I've never used setup-cygwin.el. I don't even know
what it does, so I could be missing out, but I wanted to mention that
(at least in my use case) setup-cygwin.el isn't necessary to use Cygwin
with Emacs.

        John

Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: shell-command in Windows 7

John Mastro
John Mastro <[hidden email]> wrote:

> 42 147 <[hidden email]> wrote:
>> setup-cygwin.el is perfectly compatible with the code that John Mastro
>> suggested (which works better than what I had previously anyway). I need
>> setup-cygwin.el to run cygwin in Emacs. No way I'll stop loading it!
>
> I've been using native Windows builds of Emacs together with Cygwin for
> several years now. (Eli recommends against it for very sensible reasons,
> but I haven't found anything better and it works well enough for me).
>
> During that time, I've never used setup-cygwin.el. I don't even know
> what it does, so I could be missing out, but I wanted to mention that
> (at least in my use case) setup-cygwin.el isn't necessary to use Cygwin
> with Emacs.

I should mention that I do have some home-grown Cygwin-related settings
though.

I do not claim this is the best or right way to do it, but it's what I
ended up with over time, so I'll share it FWIW.

(defvar cygwin-path-directories
  '("/bin" "/usr/bin" "/usr/local/bin"
    "/Windows" "/ProgramData/Oracle/Java/javapath"))

(defun cygwinize-file-name (name)
  (if (string-match "\\`\\([A-Za-z]\\):\\(/\\|\\\\\\)" name)
      (let* ((drive (match-string 1 name))
             (sep   (match-string 2 name))
             (more  (substring name (match-end 2))))
        (concat (if (member drive '("c" "C")) "" (concat "/" drive))
                "/"
                (if (equal sep "\\")
                    (replace-regexp-in-string "\\\\" "/" more)
                  more)))
    name))

(defun init-for-cygwin ()
  (let* ((home (cygwinize-file-name (or (getenv "HOME")
                                        (error "HOME not defined"))))
         (home/bin (concat home
                           (unless (string-suffix-p "/" home) "/")
                           "bin"))
         (path (cons home/bin cygwin-path-directories)))
    (setenv "PATH" (mapconcat #'identity path ":"))
    (setq exec-path (mapcar (lambda (dir) (concat "c:" dir)) path))
    (let ((shell (or (executable-find "zsh")
                     (executable-find "bash")
                     (error "Can't find zsh or bash"))))
      (setq shell-file-name shell)
      (setq explicit-shell-file-name shell)
      (setq ediff-shell shell)
      (setq null-device "/dev/null")
      (setenv "SHELL" shell))))

(when (and (eq system-type 'windows-nt)
           (file-executable-p "c:/bin/bash.exe"))
  (init-for-cygwin))

Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: shell-command in Windows 7

drain
I was under the impression that setup-cygwin.el was needed to run a Cygwin
shell within Emacs.

I'll admit that I set Cygwin-Emacs up by mechanically following the first
set of instructions I found online. As with everything there are apparently
many different ways of getting the same result.

Am 4/15/2017 um 10:08 PM schrieb John Mastro:

> John Mastro <[hidden email]> wrote:
>> 42 147 <[hidden email]> wrote:
>>> setup-cygwin.el is perfectly compatible with the code that John Mastro
>>> suggested (which works better than what I had previously anyway). I need
>>> setup-cygwin.el to run cygwin in Emacs. No way I'll stop loading it!
>> I've been using native Windows builds of Emacs together with Cygwin for
>> several years now. (Eli recommends against it for very sensible reasons,
>> but I haven't found anything better and it works well enough for me).
>>
>> During that time, I've never used setup-cygwin.el. I don't even know
>> what it does, so I could be missing out, but I wanted to mention that
>> (at least in my use case) setup-cygwin.el isn't necessary to use Cygwin
>> with Emacs.
> I should mention that I do have some home-grown Cygwin-related settings
> though.
>
> I do not claim this is the best or right way to do it, but it's what I
> ended up with over time, so I'll share it FWIW.
>
> (defvar cygwin-path-directories
>    '("/bin" "/usr/bin" "/usr/local/bin"
>      "/Windows" "/ProgramData/Oracle/Java/javapath"))
>
> (defun cygwinize-file-name (name)
>    (if (string-match "\\`\\([A-Za-z]\\):\\(/\\|\\\\\\)" name)
>        (let* ((drive (match-string 1 name))
>               (sep   (match-string 2 name))
>               (more  (substring name (match-end 2))))
>          (concat (if (member drive '("c" "C")) "" (concat "/" drive))
>                  "/"
>                  (if (equal sep "\\")
>                      (replace-regexp-in-string "\\\\" "/" more)
>                    more)))
>      name))
>
> (defun init-for-cygwin ()
>    (let* ((home (cygwinize-file-name (or (getenv "HOME")
>                                          (error "HOME not defined"))))
>           (home/bin (concat home
>                             (unless (string-suffix-p "/" home) "/")
>                             "bin"))
>           (path (cons home/bin cygwin-path-directories)))
>      (setenv "PATH" (mapconcat #'identity path ":"))
>      (setq exec-path (mapcar (lambda (dir) (concat "c:" dir)) path))
>      (let ((shell (or (executable-find "zsh")
>                       (executable-find "bash")
>                       (error "Can't find zsh or bash"))))
>        (setq shell-file-name shell)
>        (setq explicit-shell-file-name shell)
>        (setq ediff-shell shell)
>        (setq null-device "/dev/null")
>        (setenv "SHELL" shell))))
>
> (when (and (eq system-type 'windows-nt)
>             (file-executable-p "c:/bin/bash.exe"))
>    (init-for-cygwin))


Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

white line appears irregularly on left side of Emacs frame in GNU / Linux virtual machine

drain
In reply to this post by John Mastro
I'm running a Debian 7 virtual machine in Windows, though I had noticed
this in the past with Ubuntu and other GNU / Linux distros running in VMs.

I'm not sure if it's a VM issue, because (a) Emacs is the only program that
manifests this white line and (b) it happens in Virtual Box and in VMWare.

I've tried some of the refresh commands, but they do nothing.

If this mailing list accepts pictures, I can attach a screenshot.


Loading...