/WSLSetup

How I like to set up WSL

Primary LanguageAutoHotkey

Windows 10 WSL setup

WSL is nice on its own, but I’ve found a few ways to make it integrate with Windows a lot nicer! So this is what I do when I set up WSL!

Symlinks

The first thing I do when I set up a new WSL instance is make a few symlinks between the two systems.

The first one is for the root drive (Requires root):

ln -s /mnt/c /host

Then I add a few folders in my home folder that make the link between Windows and Linux pretty seamless. (If you already have these folders, you might need to move or nuke them first)

If you aren’t running this from Emacs, you can hit [Windows] + [R], type ”%userprofile%” and hit [Enter]. Then hit [Ctrl] + [L] type ”bash” and [Enter] again. This should put you in correct folder this should be run from.

for i in Desktop Documents Downloads Videos Music Pictures; do
  ln -s $i ~
done

mkdir ~/Documents/Code ~/Documents/Writing
ln -s ~/Documents/Code ~/Documents/Writing ~

Base programs

After installing Chocolatey, installing some essential programs can be done from the following in an elevated command prompt.

choco install xming autohotkey wsltty -y

And after that’s done, the wsltty terminal can be set up with the following:

C:\ProgramData\Chocolatey\lib\wsltty\tools\wslttyinstall\install.bat

My configuration for wsltty is basically just to make it look like a simple and slightly transparent terminal: ./mintty.png

This goes in %APPDATA%\wsltty\config

ThemeFile=dainty-monokai-night-mod
Transparency=5
OpaqueWhenFocused=no
CursorType=block
Font=Consolas
FontHeight=11
ZoomShortcuts=no
AltFnShortcuts=no
BackgroundColour=0,0,0

The above theme is follows, and goes in %APPDATA%\wsltty\themes\dainty-monokai-night-mod (Originally from here, and modified slightly for contrast):

# source: https://github.com/alexanderte/dainty-wsltty
# MIT License

BackgroundColour=40, 40, 40
Black=51, 51, 51
Blue=106, 126, 200
BoldBlack=102, 102, 102
BoldBlue=129, 154, 255
BoldCyan=102, 217, 239
BoldGreen=166, 226, 46
BoldMagenta=195, 159, 255
BoldRed=249, 38, 114
BoldWhite=248, 248, 242
BoldYellow=226, 226, 46
CursorColour=248, 248, 240
Cyan=86, 173, 188
ForegroundColour=222, 222, 222
Green=134, 180, 43
Magenta=195, 159, 255
Red=196, 38, 94
White=227, 227, 221
Yellow=179, 180, 43

For XMing, I update my .Xresources file to get a slightly nicer looking X11:

Xft.antialias: 1
Xft.dpi: 96
Xft.hinting: 1
Xft.hintstyle: hintsfull
Xft.lcdfilter: lcddefault
Xft.rgba: rgb

Then I edit my ~/.profile to include things like the following at the end:

# Allow graphical Linux programs to know how to connect to XMing
export DISPLAY=127.0.0.1:0

# Make XMing look nicer
xrdb -merge $HOME/.Xresources

For AutoHotKey, I make a little script to start wsltty when I hit Ctrl + Alt + T, just like the default keybinding in a lot of Linux window managers.

^!t::
    Run, C:\Users\Archenoth\AppData\Local\wsltty\bin\mintty.exe --WSL= --configdir="%APPDATA%\wsltty" -~
Return

I also make a little vbscript file to run XMing, and then to start bash once (to run my .profile with the Linux-side XMing configuration):

CreateObject("Wscript.Shell").Run """C:\Program Files (x86)\Xming\Xming.exe"" :0 -clipboard -multiwindow", 0, False
CreateObject("Wscript.Shell").Run "bash -lic exit", 0, True

After making these, I copy shortcuts for that last two scripts above into my shell:startup folder. (You can access by typing that into the run dialog you get by hitting Win + R)

That will make this stuff all start on login, and without popping up any ugly command windows on startup. (That’s why I used vbscript here–to squelch the command prompt popups)

Startup services

To get Linux services starting on Windows start (Before anyone logs in), I create a startup script in etc named after the user that will run it, so in my case, I call it rc.arch.local:

#!/bin/bash
service cron start
service ssh start

I then add my user to a sudoers files to allow this to be run as root without a password:

# Startup script access for default user
archenoth ALL=(root) NOPASSWD: /etc/rc.arch.local

In Windows, I open up the Task Scheduler and make scheduled tasks to run the /etc/rc.arch.local file with passwordless sudo when the computer starts.

This is what the task I made looks like exported as XML (You may need to change the user in here if you are planning on importing it into your Task Scheduler):

<?xml version="1.0" encoding="UTF-16"?>
<Task version="1.2" xmlns="http://schemas.microsoft.com/windows/2004/02/mit/task">
  <RegistrationInfo>
    <Date>2019-11-08T12:49:06.8481246</Date>
    <Author>JIRACHI\Archenoth</Author>
    <Description>Starts the Linux Subsystem rc.arch.local script</Description>
    <URI>\WSL rc.arch.local</URI>
  </RegistrationInfo>
  <Triggers>
    <BootTrigger>
      <Enabled>true</Enabled>
    </BootTrigger>
  </Triggers>
  <Principals>
    <Principal id="Author">
      <UserId>S-1-5-21-3695860422-1816032588-548272057-1001</UserId>
      <LogonType>S4U</LogonType>
      <RunLevel>LeastPrivilege</RunLevel>
    </Principal>
  </Principals>
  <Settings>
    <MultipleInstancesPolicy>IgnoreNew</MultipleInstancesPolicy>
    <DisallowStartIfOnBatteries>false</DisallowStartIfOnBatteries>
    <StopIfGoingOnBatteries>true</StopIfGoingOnBatteries>
    <AllowHardTerminate>true</AllowHardTerminate>
    <StartWhenAvailable>true</StartWhenAvailable>
    <RunOnlyIfNetworkAvailable>false</RunOnlyIfNetworkAvailable>
    <IdleSettings>
      <StopOnIdleEnd>true</StopOnIdleEnd>
      <RestartOnIdle>false</RestartOnIdle>
    </IdleSettings>
    <AllowStartOnDemand>true</AllowStartOnDemand>
    <Enabled>true</Enabled>
    <Hidden>false</Hidden>
    <RunOnlyIfIdle>false</RunOnlyIfIdle>
    <WakeToRun>false</WakeToRun>
    <ExecutionTimeLimit>PT72H</ExecutionTimeLimit>
    <Priority>7</Priority>
  </Settings>
  <Actions Context="Author">
    <Exec>
      <Command>C:\Windows\System32\bash.exe</Command>
      <Arguments>-c "sudo /etc/rc.arch.local"</Arguments>
    </Exec>
  </Actions>
</Task>

I didn’t bother with vbscript for this one since it runs before I even log on, so there still aren’t any command prompt popups.

And that about covers the main tweaks I make! Feel free to steal as many of these ideas as you like..! ^^

Tweaks

These aren’t as major, but they are nice little things I sometimes enjoy being able to use.

Using Linux programs from cmd.exe

I wrote a little Windows binary that, if you rename it to a Linux command, that Linux command will run. So if you like having git.exe on your path, you can use the Linux version with your Linux SSH config.

To set it up, you can run the following:

mkdir -p /host/Oshawott/bin
wget https://github.com/Archenoth/wsl_proxy/releases/download/0.2.0/wsl_proxy.exe -O /host/Oshawott/wsl_proxy.exe

remaining=1023
find /bin /usr/bin /usr/local/bin /usr/sbin -executable -type f -maxdepth 1 ! -name bash -printf "%f\n" \
    | sort | uniq | while read bin; do
    echo "Linking $bin"
    if [ "$remaining" -le "0" ]; then
        remaining=1023
        cp /host/Oshawott/wsl_proxy.exe /host/Oshawott/wsl_proxy2.exe
        mv /host/Oshawott/wsl_proxy.exe "/host/Oshawott/bin/$bin.exe"
        mv /host/Oshawott/wsl_proxy2.exe /host/Oshawott/wsl_proxy.exe
    else
        remaining=$((remaining-1))
        ln /host/Oshawott/wsl_proxy.exe "/host/Oshawott/bin/$bin.exe"
    fi
done

This will download the wsl_proxy.exe program, and link every executable in a number of bin folders likely on your $PATH. (We aren’t gonna use $PATH proper since it will return many executables that aren’t actually if you have any Windows paths in there)

The 1023 links per copy business is because each file can have only a maximum of 1024 links at any given time. (And yes, WSL hardlinks work on Windows)

To use this, you’ll need to change your “Path” in sysdm.cpl under “Advanced” -> “Environment Variables” -> “User variables for <you>” to include C:\Oshawott\bin.

Run exes without writing “.exe”

You can use command_not_found_handle to automatically append .exe to your commands if they don’t exist on Linux and try again. All you need to do is modify the handle in bash.bashrc to look like:

if [ -x /usr/lib/command-not-found -o -x /usr/share/command-not-found/command-not-found ]; then
    function command_not_found_handle {
        if which "$1.exe" 1>/dev/null 2>&1; then
            EXE="$1.exe"
            shift
            $EXE $*
            return $?
        else
            # check because c-n-f could've been removed in the meantime
            if [ -x /usr/lib/command-not-found ]; then
                /usr/lib/command-not-found -- "$1"
                return $?
            elif [ -x /usr/share/command-not-found/command-not-found ]; then
                /usr/share/command-not-found/command-not-found -- "$1"
                return $?
            else
                printf "%s: command not found\n" "$1" >&2
                return 127
            fi
        fi
    }
fi

Since WSL does pathname translation, this means you can do crazy things like explorer Code/ahk and it will open that code folder with explorer.exe properly if it’s in your $PATH!

Note: Programs run this way won’t work on paths that only WSL can see. Which is another good reason to have symlinks between your two systems set up!

Turn off dings every time you hit tab (And other things)

I don’t really like how tab completion, or many other actions in Linux make my computer ding at me, so I like to replace the bell-style in /etc/inputrc to be set bell-style none.

Conclusion

I mostly wrote this file for myself, but if you stumbled across it somehow, I hope you found these tricks useful!