3

From Windows 10, how can I call an Emacs instance residing on a Windows 10 WSL 2 Linux install, passing it a given file to visit?

So far, I've done this:

On my WSL 2 Linux, I've created a script called runemacs.sh which I keep in ~/bin/

It sets some needed environment variables, to make libgl happy and to tell Emacs where my Windowds 10 X server is. It looks like this:

#!/bin/sh
    
export LIBGL_ALWAYS_INDIRECT=1
export DISPLAY=$(cat /etc/resolv.conf | grep nameserver | awk '{print $2}'):0
    
setsid emacs $1

I can then open a graphical Emacs client from Windows 10 using a command like the following from a Windows Powershell or Command prompt:

wsl -e /home/ld/bin/runemacs.sh

This brings up the Emacs graphical client on my windows desktop.

What I can't do, is then tell Emacs what file I want to edit. If I have a file named test.txt on my Windows 10 file system for example, I can't then run this to open that file in Windows:

 wsl -e /home/ld/bin/runemacs.sh --file=test.txt

It makes sense why this wouldn't work. I am basically telling Emacs to open test.txt on the WSL 2 Linux install. But this is as far as I've been able to figure out how to go myself.

How can I tell Emacs which file to edit?

UPDATE 1: I was able to get much further from Tobias's help. But I am still left unable to ultimately call wsl's emacs from Windows using 'wsl' combined with 'wslpath'.

I can call wslpath directly from wsl and get a correctly formatted path by doing the following from Windows:

PS C:\> wsl -e wslpath -u "d:\lorddevi\Documents\OpenBSD-Notes.md"
/mnt/d/lorddevi/Documents/OpenBSD-Notes.md

The 2nd line there being the output. Which, if I could pass to emacs on wsl, it would open fine.

However, I can't use command expansion quotes ( `` ) that I would normally use in a Bash script or on the command line, but can't from windows.

If I try to perform that expansion by creating a bash script on WSL in my homedir, and calling it from Windows, the slashes get trimmed from the pathname for some reason.

Such as:

PS C:> wsl ~/bin/wslemacs.sh d:\lorddevi\Documents\OpenBSD-Notes.md /mnt/d/lorddeviDocumentsOpenBSD-Notes.md

I can't use -e here as I normally would and still call a bash script I guess. I tried and it just quietly dies.

So I've tried everything at this point that I can think of to get wslpath to work for me. I am SO close.

If I could either:

  1. Use `` command expansion quotes for the wslpath call I could make this work.

  2. Or if I could call my 'wslemacs.sh c:\pathto\file.txt' script with windows' wsl.exe command I could also get this working I think.

But neither work, and i am once more lost. :(

8
  • Can 'wslpath` help you?
    – Tobias
    Commented Jun 23, 2020 at 14:58
  • I don't think so. I think in order to even use wslpath at all, I would run into the same problem. How do I pass an option to wslpath that is a reference to a file not on the WSL subsystem?
    – Lord_Devi
    Commented Jun 24, 2020 at 10:19
  • Did you try? Just pass the full windows file path to wslpath on WSL.
    – Tobias
    Commented Jun 24, 2020 at 11:10
  • WSL is not an ideal system. I once installed Cygwin Emacs residing on Cygwin but then I removed it along with the Cygwin because of some incompatibility. Ive been using the native Windows Emacs ever since and never had any problems so far. Just my two cents.
    – Terry
    Commented Jun 25, 2020 at 11:16
  • Thanks to Tobias I was able to get a lot closer. But still not quite there. :(
    – Lord_Devi
    Commented Jul 1, 2020 at 15:41

2 Answers 2

1

This works on my WSL 2 with debian 10 and emacs 28.0.5

My batch script runemacs.bat(calling a few powershell commands inside):

@echo OFF

:: Get the given path to file
set givenPath=%*

:: Get absolute path to target file
for /f "delims=" %%a in ('powershell -Command "[System.IO.Path]::GetFullPath( '%givenPath%' )"') do @set resolvedPath=%%a

:: Double the backquotes in both the file path and the current dir path
for /f "delims=" %%a in ('powershell -Command "$a = '%resolvedPath%'; echo $a.replace('\', '\\');"') do @set resolvedPath=%%a
for /f "delims=" %%a in ('powershell -Command "$a = '%CD%'; echo $a.replace('\', '\\');"') do @set currentDirPath=%%a

:: Call bash script with backquotted paths
debian.exe run /home/myhome/bin/runemacs.sh "%resolvedPath%" "%currentDirPath%"

My bash script runemacs.sh:

#!/usr/bin/env bash

export DISPLAY=127.0.0.1:0.0
FILENAME=$(wslpath -u "$1")
setsid /home/matt/opt/emacs/bin/emacs "$FILENAME"

In cmd.exe just type

runemacs.sh

to open emacs in the current directory, or

runemacs.sh file_or_dir_path

Where file_or_dir_path can be either relative or absolute.

0

I finally managed to get this working in an extremely hacky way. The below is how I did it, requiring four scripts -- two batch files, one VBscript (to make sure the batch window doesn't hang around), and one shell script. Additionally, the utilities from https://wslutiliti.es/ are necessary for the final step, to convert the Windows path into a Linux path.

open_with_emacs_launch.bat:

@echo off
wscript C:\Users\Zeta\bin\open_with_emacs.vbs "%~1"

open_with_emacs.vbs:

Set WshShell = CreateObject("WScript.Shell") 
WshShell.Run """C:\Users\Zeta\bin\open_with_emacs.bat"" """ & WScript.Arguments.Item(0) & """", 0
Set WshShell = Nothing

open_with_emacs.bat:

@echo off
wsl /mnt/c/Users/Zeta/bin/open_with_emacs.sh "%~1"

open_with_emacs.sh:

cd ~
export DISPLAY=$(ip route | awk '{print $3; exit}'):0
export LIBGL_ALWAYS_INDIRECT=1

path=`wslpath -u "$1"`
emacsclient -c -a 'emacs' "$path"

The launch script is there because Windows 10 won't let me set the .vbs as a default application to launch with -- it throws an error. Instead, the batch file passes the file we're trying to open to the .vbs. The .vbs opens the next batch file silently, so we don't have an ugly console window hanging around with Emacs. The final batch file calls WSL with a command to open the shell script, which then converts the path into a Linux native path and executes Emacs.

It's hacky as heck, and I'm 100% positive there's a better way to do all of it. But it does work, and it's here if anyone else wants to use it. Obviously edit your variables for whatever Xserver you're using.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.