File associations in Windows [was: Re: Invoking Cygwin vim from Windows Explorer]

Max Polk maxpolk@gmail.com
Mon Feb 10 04:08:00 GMT 2014


On 2/9/2014 12:11 PM, carolus wrote:
 > Is there some configuration that will let me open a text file
 > in Cygwin vim by clicking on the file in an Explorer window?

I wonder if anyone else needs Windows file associations for sequences of 
Cygwin commands as well.  If this is useful to many, maybe a nice 
utility can be whipped up.  I ran into this with emacs-w32.exe which is 
the Cygwin emacs compiled for Win32 (not run under X).

(I require native Cygwin emacs, not the one downloaded from ftp.gnu.org, 
because version control things like bzr which are Python scripts aren't 
supported by Windows emacs, and because in general I want Cygwin, not 
Windows filenames, and so forth.)

The first problem is that Windows file associations have to be a single 
exe with no arguments.  When you run that file (double click in 
Explorer), Windows passes the filename to that single .exe program.

The second problem is that it might need to be started from a full login 
shell (run from bash, after .bashrc and .bash_profile are loaded) to get 
right env vars and paths and other things to be set. No, I don't want to 
pollute Windows environment by duplicating everything I do in .bashrc 
and .bash_profile.  So yes, I really need to run emacs from bash run as 
full login shell.

Why full login shell?  When I run emacs-w32.exe, things like version 
control programs need the full login shell env vars, because checking 
the current directory under vc-dir doesn't run a shell, it runs "cvs" or 
"svn" or "git" directly.  Without the full login shell, you don't have 
an env vars set.  Fail.

No, I don't want to pollute my ~/.emacs with lots of (setenv "MYVAR" 
"myvalue") to mirror what's in .bashrc and .bash_profile, then monkeying 
with load-path and many other ugly hacks.  Again, duplicating .bashrc 
and .bash_profile I dislike.

So in the end, my emacs start menu link is normally this:
Target: C:\Apps\Cyg\usr\local\bin\run.exe /bin/bash --login -i -c emacs
Start in: C:\Apps\Cyg\bin

(The patch for run.exe for quoting args better is accepted but not yet 
out there, so it's a locally compiled one for now.  Because 
/usr/local/bin/run doesn't have the cygwin1.dll it won't start when 
located elsewhere.  Ignore, secondary issue.)

The third problem is that the file passed to the Windows file 
association program is in Windows form, not Cygwin form with mounted 
filename substitutions (eg, I have /c for C:\).  Many Cygwin programs if 
you pass C:\X\y will see C:Xy.

So to get a .txt file association to work with emacs-w32.exe, and also 
to get it to run under a full bash shell, and also to replace Windows 
with Cygwin file format, we need a single .exe that does all that.  I 
ask, are others wanting to run random sequences of Cygwin programs as 
file associations?  If so, maybe a little utility is in order.

I wrote a little utility of my own, a C++ program that essentially does:
cd C:\Apps\Cyg\bin
C:\Apps\Cyg\usr\local\bin\run.exe /bin/bash --login -i -c "emacs 
C:/X/My\ File.txt"

The "C:\X\My File.txt" replaced back with forward slashes, so slashed 
aren't lost to the Cygwin application, and escapes space with backslash 
space so it doesn't look like separate files to emacs.

After assembling where cygwin lives based on a personal env var 
"CYGROOT" into cygbin ostringstream:
     if (chdir (cygbin.str ().c_str ())) { ...error... }

After assembling the run argument as "runexe" ostringstream, and the 
bash login emacs argument as "cmd" ostringstream, in the end it did 
this, which might be useful for a little utility if someone wants to run 
with this:

     // Create an array with length 3 (2 plus null array terminator)
     char ** newAv = (char **)malloc (sizeof (char *) * 3);

     // First element of array is 'run'
     newAv[0] = (char *)malloc (strlen (runexe.c_str ()) + 1);
     strcpy (newAv[0], runexe.c_str ());

     // Second element of array is the bash command to launch emacs with 
args
     newAv[1] = (char *)malloc (strlen (cmd.str ().c_str ()) + 1);
     strcpy (newAv[1], cmd.str ().c_str ());

     // Third element of array is null terminator
     newAv[2] = 0;

     // Report what we are doing in case someone is watching
     printf ("%s\n", newAv[1]);

     // Replace this process with 'run' process
     execve (newAv[0], newAv, env);

To get emacs to parse the C:\whatever as /c/whatever (since I mounted /c 
as C:\):

; When in cygwin, allow C:\whatever to turn into /c/whatever
(defun cygwin-name-hook (operation &rest args)
   "Turn Windows filenames into Cygwin filenames."
   ;; Handle all operations the same
   (let ((first (car args))
         (inhibit-file-name-handlers
          (cons 'cygwin-name-hook
                (and (eq inhibit-file-name-operation operation)
                     inhibit-file-name-handlers)))
         (inhibit-file-name-operation operation))
     (setq first (replace-regexp-in-string "^C:" "/c" first t))
     (setq first (replace-regexp-in-string "\\\\" "/" first t))
     (apply operation (cons first (cdr args)))))

(add-to-list 'file-name-handler-alist '("^[Cc]:" . cygwin-name-hook))

This also lets emacs be passed a Windows filename from places like 
compiler output errors, and it loads the right one.

For my C++ little utility I copied the emacs.ico and created a tiny 
LaunchEmacs.rc referencing it (so the "launch" file association looks 
like Emacs).  Finally the Makefile was:

     i686-pc-mingw32-windres LaunchEmacs.rc -O coff -o LaunchEmacs.res
     i686-pc-mingw32-g++ -static -mwindows -o LaunchEmacs.exe 
LaunchEmacs.cc LaunchEmacs.res

As you can see, this is a lot of work, and it may be useful to have 
Cygwin support file associations where some utility will go all the way 
with filename conversion, launching, full login shell support, and whatnot.

Are people interested?  Enough to start a little utility for this?

--
Problem reports:       http://cygwin.com/problems.html
FAQ:                   http://cygwin.com/faq/
Documentation:         http://cygwin.com/docs.html
Unsubscribe info:      http://cygwin.com/ml/#unsubscribe-simple



More information about the Cygwin mailing list