4

I am very new to Lisp - and Elisp especially - and I have a problem with string handling:

I want to convert a Windows style path to a Unix style path - especially I need to convert a path I get from Visual Studio to a Cygwin path, as I want to be able to open a file from Visual Studio in Emacs (I hope to use emacsclient --eval for this):

The Visual Studio path has the following format:

C:\Users\name\documents\visual studio 2010\projects\test

I want to change it into the appropriate Cygwin path which would be:

/cygdrive/c/Users/name/documents/visual studio 2010/projects/test

However trying the following in the scratch-buffer already fails:

(replace-regexp-in-string "\\" "\/" "C:\users\someone")
(subst-char-in-string ?\ ?/ "C:\users\someone")

>> Debugger entered--Lisp error: (error "Non-hex digit used for Unicode escape")

Is there any way to make Elisp not escape the backslashes in every string?

EDIT:

Here is how I call emacs from Visual Studio via external tools:

emacsclient -d 127.0.0.1:0.0 --eval '(convert-win-to-cygwin-path $(ItemPath))'

$(ItemPath) will be replaced with C:\Users\asf which I can not influence - so it will pass a String with single backslashes to emacs that I need to modify in emacs.

Can I make emacs KNOW that it needs to make double backslashes out of the single backslashes?

EDIT 2: Solution

I changed the way I attempt to start emacs by actually calling a shell-script that will start emacs - this way I can make sure that emacs gets the right path:

#!/bin/bash

export PATH="/usr/bin/:/bin/:$PATH"

filename=$1
line=$2
column=$3

cyged_path=$(cygpath "$filename")

echo "Cyged path: $cyged_path"

emacsclient -d 127.0.0.1:0.0 -n +$line:$column "$cyged_path"

And I call it from Visual Studio with the following arguments in the external tools window:

Path: <path_to_cygwin>\bin\bash.exe
Arguments: <path_to_script> $(ItemPath) $(CurLine) $(CurCol)
BergmannF
  • 9,727
  • 3
  • 37
  • 37
  • To double the backslashes, ask Emacs to read it into a string in the minibuffer, instead of pasting it directly into Emacs. You cannot get `C:\users` into a literal string without doubling the backslash one way or another (`\u` has a special meaning in Emacs strings; it is the beginning of a Unicode sequence). – tripleee Oct 16 '12 at 09:25

6 Answers6

3

You don't need to do any of that.

Cygwin provides a command specifically for converting Windows paths to Cygwin paths, so that you don't need to bother about this sort of thing.

cmd> C:\cygwin\bin\cygpath.exe "C:\Users\name\documents\visual studio 2010\projects\test"

/cygdrive/c/Users/name/documents/visual studio 2010/projects/test

Edit: I was curious about a Windows shell equivalent of backticks, and found Batch equivalent of Bash backticks, which suggests you might be able to do it all with this one-liner?

cmd> for /f "usebackq tokens=*" %a in (`C:\cygwin\bin\cygpath.exe "$(ItemPath)"`) do emacsclient -d 127.0.0.1:0.0 "%a"
Community
  • 1
  • 1
phils
  • 71,335
  • 11
  • 153
  • 198
  • That helped - I just had to put it into a shell-script that is called from visual studio that will start the ``emacsclient``. – BergmannF Oct 16 '12 at 10:53
1

Another way to look at your problem is that your emacsclient -d 127.0.0.1:0.0 --eval '(convert-win-to-cygwin-path $(ItemPath))' passes the file name inside an Elisp string, which is why the backslashes are treated as escapes. So the solution is to pass it as data, as in emacsclient -d 127.0.0.1:0.0 $(ItemPath). The next problem is to make your Emacs understand those filenames. If you use the normal Windows build of Emacs that will work without doing anything special, but if you use the Cygwin build, you'll need to do something like the equivalent (but in reverse) of cygwin-mout.el.

Stefan
  • 27,908
  • 4
  • 53
  • 82
  • Would passing $(ItemPath) as first argument not simply pass it as the file to open which would not work as it would have the windows and not the cygwin-filepath? – BergmannF Oct 17 '12 at 08:20
  • Yes it would pass it as a file name, but I suggest you teach Emacs to understand Windows file names (just like `cygwin-mount.el` teaches Windows Emacs to understand Cygwin file names). – Stefan Oct 17 '12 at 20:35
1

Here's the answer in emacs lisp, even though I like Phils answer. This function converts the region which is expected to be a full windows filepath including the drive, into a cygwin path.

For example:

C:\Users\name\documents\visual studio 2010\projects\test

becomes...

/cygdrive/C/Users/name/documents/visual studio 2010/projects/test

Here's the code:

(defun win32-to-cygwin-path()
  "Converts a win32 path into a cygwin happy one"
  (interactive)
  (save-excursion
    (save-restriction
      (narrow-to-region (point) (mark))
      (goto-char (point-min))
      (insert "/cygdrive/")
      (goto-char (point-min))
      (while (search-forward ":" nil t)
    (replace-match "" nil t))
      (while (search-forward "\\" nil t)
    (replace-match "/" nil t)))))
justinhj
  • 11,147
  • 11
  • 58
  • 104
0

A backslash needs to be escaped. This would work:

ELISP> (subst-char-in-string ?\\ ?/ "C:\\users\\someone")
"C:/users/someone"
Rainer Joswig
  • 136,269
  • 10
  • 221
  • 346
  • The problem is that Visual Studio will only pass single backslahes in the filepath - that is the main problem. – BergmannF Oct 16 '12 at 09:07
  • 1
    @Gjallar: Then you need to convert them to double backslashes. The Emacs Lisp reader uses backslash as an escape character in strings. – Rainer Joswig Oct 16 '12 at 09:11
  • I added a clarification to the question - the path is inserted by visual studio and I can not modify it. – BergmannF Oct 16 '12 at 09:23
0

Are you sure Windows isn't sending preescaped backslashes? It would be strange if it didn't do that.

See this wiki page for how other have solved this problem.

event_jr
  • 17,467
  • 4
  • 47
  • 62
0

None of these solutions worked for me (emacs 24.3.1), anyway, a simple .bat script will do:

@ECHO OFF

c:\cygwin64\bin\cygpath.exe %1 > tmp.txt
set /p FILE_TO_EDIT= < tmp.txt
del tmp.txt
C:\cygwin64\bin\cygstart.exe -- /bin/emacs-w32.exe %FILE_TO_EDIT%

Save that in a file.bat and send the file you want to edit as the argument, for WinSCP, will look like: C:\Users\xxxxx\Desktop\open.bat !.!

Alfonso
  • 21
  • 1