Windows pain (#336)
* blog: start on windows pain post Signed-off-by: Christine Dodrill <me@christine.website> * flags Signed-off-by: Christine Dodrill <me@christine.website> * more Signed-off-by: Christine Dodrill <me@christine.website> * yse Signed-off-by: Christine Dodrill <me@christine.website>
This commit is contained in:
parent
b10c097504
commit
08865c84b6
|
@ -0,0 +1,291 @@
|
|||
---
|
||||
title: "Development on Windows is Painful"
|
||||
date: 2021-03-03
|
||||
tags:
|
||||
- windows
|
||||
- vscode
|
||||
- nix
|
||||
- emacs
|
||||
- rant
|
||||
---
|
||||
|
||||
# Development on Windows is Painful
|
||||
|
||||
<big>SUBJECTIVITY WARNING</big>
|
||||
|
||||
This post contains opinions. They may differ from the opinions you hold, and
|
||||
that's great. This post is not targeted at any individual person or
|
||||
organization. This is a record of my frustration at trying to get Windows to do
|
||||
what I consider "basic development tasks". Your experiences can and probably
|
||||
will differ. As a reminder, I am speaking for myself, not any employer (past,
|
||||
present and future). I am not trying to shit on anyone here or disregard the
|
||||
contributions that people have made. This is coming from a place of passion for
|
||||
the craft of computering.
|
||||
|
||||
With me using VR more and more [with my Quest 2 set up with
|
||||
SteamVR](/blog/convoluted-vrchat-gchat-setup-2021-02-24), I've had to use
|
||||
windows more on a regular basis. It seems that in order to use [Virtual
|
||||
Desktop](https://www.vrdesktop.net), I **MUST** have Windows as the main OS on
|
||||
my machine for this to work. Here is a record of my pain and suffering trying to
|
||||
do what I consider "basic" development tasks.
|
||||
|
||||
## Text Editor
|
||||
|
||||
I am a tortured soul that literally thinks in terms of Vim motions. This allows
|
||||
me to be mostly keyboard-only when I am deep into hacking at things, which
|
||||
really helps maintain flow state because I do not need to move my hands or look
|
||||
at anything but the input line right in front of me. Additionally, I have gotten
|
||||
_very_ used to my Emacs setup, and specifically the subtle minutae of how it
|
||||
handles its Vim emulation mode and all of the quirks involved.
|
||||
|
||||
I have tried to use my Emacs config on Windows (and barring the things that are
|
||||
obviously impossible such as getting Nix to work with Windows) and have
|
||||
concluded that it is a fantastic waste of my time to do this. There are just too
|
||||
many things that have to be changed from my Linux/macOS config. That's okay, I
|
||||
can just use [VSCode](https://code.visualstudio.com) like a bunch of apologists
|
||||
have been egging me into right? It's worked pretty great for doing work stuff on
|
||||
NixOS, so it should probably be fine on Windows, right?
|
||||
|
||||
### Vim Emulation
|
||||
|
||||
So let's try opening VSCode and activating the Vim plugin
|
||||
[vscodevim](https://marketplace.visualstudio.com/items?itemName=vscodevim.vim).
|
||||
I get that installed (and the gruvbox theme because I absolutely love the
|
||||
Gruvbox aesthetics) and then open VSCode in a new folder. I can `:open` a new
|
||||
file and then type something in it. Then I want to open another file split to
|
||||
the left with `:vsplit`, so I press escape and type in `:vsplit bar.txt`.
|
||||
Then I get a vsplit of the current buffer, not the new file that I actually
|
||||
wanted. Now, this is probably a very niche thing that I am used to (even though
|
||||
it works fine on vanilla vim and with evil-mode), and other people I have asked
|
||||
about this apparently do not open new files like that (and one was surprised to
|
||||
find out that worked at all); but this is a pretty heavily ingrained into my
|
||||
muscle memory thing and it is frustrating. I have to retrain my decade old
|
||||
buffer management muscle memory.
|
||||
|
||||
#### Whichwrap
|
||||
|
||||
Vim has a feature called whichwrap that lets you use the arrow keys at the
|
||||
end/beginning of lines to go to the beginning/end of the next/previous line. I
|
||||
had set this in my vim config [in November
|
||||
2013](https://github.com/Xe/dotfiles/commit/d8301453c2b61846eea8305b9ed4b80f498f3838)
|
||||
and promptly forgotten about it. This lead me to believe that this was Vim's
|
||||
default behavior.
|
||||
|
||||
It apparently is not.
|
||||
|
||||
In order to fix this, I had to open the VSCode settings.json file and add the
|
||||
following to it:
|
||||
|
||||
```json
|
||||
{
|
||||
"vim.whichwrap": "h,l,<,>,[,]"
|
||||
}
|
||||
```
|
||||
|
||||
Annoying, but setting this made it work like I expected.
|
||||
|
||||
#### Kill Register != Clipboard
|
||||
|
||||
Vim has the concept of registers, which are basically named/unnamed places that
|
||||
can be used like the clipboard in most desktop environments. In my Emacs config,
|
||||
the clipboard and the kill register* are identical. If I yank a region of text
|
||||
into the kill register, it's put into the clipboard. If I copy something into
|
||||
the clipboard, it's automagically put into the kill register. It's really
|
||||
convenient this way.
|
||||
|
||||
[*It's called the "kill register" here because the vim motions for manipulating
|
||||
it are `y` to yank something into the kill register and `p` to put it into a
|
||||
different part of the document. `d` and other motions like it also put the
|
||||
things they remove into the kill register.](conversation://Mara/hacker)
|
||||
|
||||
vscodevim doesn't do this by default, however there is another setting that you
|
||||
can use to do this:
|
||||
|
||||
```json
|
||||
{
|
||||
"vim.useSystemClipboard": true
|
||||
}
|
||||
```
|
||||
|
||||
And then you can get the kill register to work like you'd expect.
|
||||
|
||||
### Load Order of Extensions
|
||||
|
||||
Emacs lets you control the load order of extensions. This can be useful to have
|
||||
the project-local config extension load before the language support extension,
|
||||
meaning that the right environment variables can be set before the language
|
||||
server runs.
|
||||
|
||||
As far as I can tell you just can't configure this. For a work thing I've had to
|
||||
resort to disabling the Go extension, reloading VSCode, waiting for the direnv
|
||||
settings to kick in and re-enabling the Go extension. This would be _so much
|
||||
easier_ if I could just say "hey you go after this is done", but apparently this
|
||||
is not something VSCode lets you control. Please correct me if I am wrong.
|
||||
|
||||
## Development Tools
|
||||
|
||||
This is probably where I'm going to get a lot more pedantic than I was
|
||||
previously. I'm used to [st](https://st.suckless.org) as my terminal emulator
|
||||
and [fish](https://fishshell.com) as my shell. This is actually a _really nice_
|
||||
combo in practice because st loads instantly and fish has some great features
|
||||
like autocomplete based on shell history. Not to mention st allowing you to
|
||||
directly select-to-copy and right-click to paste, which makes it even more
|
||||
convenient to move text around quickly.
|
||||
|
||||
### Git
|
||||
|
||||
Git is not a part of the default development tooling setup. This was surprising.
|
||||
When I installed Git manually from its website, I let it run and do its thing,
|
||||
but then I realized it installed its own copy of bash, perl and coreutils. This
|
||||
shouldn't have surprised me (a lot of Git's command line interface is written in
|
||||
perl and shell scripts), but it was the 3rd copy of bash that I had installed on
|
||||
the system.
|
||||
|
||||
As a NixOS user, this probably shouldn't have bothered me. On NixOS I currently
|
||||
have at least 8 copies of bash correlating to various versions of my tower's
|
||||
configuration. However, those copies are mostly there so that I can revert
|
||||
changes and then be able to go back to an older system setup. This is 3 copies
|
||||
of bash that are all in active use, but they don't really know about eachother
|
||||
(and the programs that are using them are arguably correct in doing this really
|
||||
defensively with their own versions of things so that there's less of a
|
||||
compatibility tesseract).
|
||||
|
||||
Once I got it set up though, I was able to do git operations as normal. I was
|
||||
also pleasantly surprised to find that ssh and more importantly ssh-keygen were
|
||||
installed by default on Windows. That was really convenient and probably avoided
|
||||
me having to install another copy of bash.
|
||||
|
||||
### Windows Terminal
|
||||
|
||||
Windows Terminal gets a lot of things very right and also gets a lot of things
|
||||
very wrong. I was so happy to see that it had claimed it was mostly compatible
|
||||
with xterm. My usual test for these things is to open a curses app that uses
|
||||
the mouse (such as Weechat or terminal Emacs) and click on things. This usually
|
||||
separates the wheat from the chaff when it comes to compatible terminal
|
||||
emulators. I used the SSH key from before to log into my server, connected to my
|
||||
long-standing tmux session and then clicked on a channel name in Weechat.
|
||||
|
||||
Nothing happened.
|
||||
|
||||
I clicked again to be sure, nothing happened.
|
||||
|
||||
I was really confused, then I started doing some digging and found [this GitHub
|
||||
comment on the Windows Terminal
|
||||
repo](https://github.com/microsoft/terminal/issues/376#issuecomment-759285574).
|
||||
|
||||
Okay, so the version of ssh that came with Windows is apparently too old. I can
|
||||
understand that. When you bring something into the core system for things like
|
||||
Windows you generally need to lock it at an older version so that you can be
|
||||
sure that it says feature-compatible for years. This is not always the best life
|
||||
decision, but it's one of the tradeoffs you have to make when you have long-term
|
||||
support for things. It suggested I download a newer version of OpenSSH and tried
|
||||
using that.
|
||||
|
||||
I downloaded the zipfile and I was greeted with a bunch of binaries in a folder
|
||||
with no obvious instructions on how to install them. Okay, makes sense, it's a
|
||||
core part of the system and this is probably how they get the binaries around to
|
||||
slipstream them into other parts of the Windows image build. An earlier comment
|
||||
in the thread suggested this was fixed with Windows Subsystem for Linux, so
|
||||
let's give that a try.
|
||||
|
||||
### Windows Subsystem for Linux
|
||||
|
||||
Windows Subsystem for Linux is a technical marvel. It makes dealing with Windows
|
||||
a lot easier. If only it didn't railroad you into Ubuntu in the process. Now
|
||||
don't get me wrong, Ubuntu works. It's boring. If you need to do something on a
|
||||
Linux system, nobody would get fired for suggesting Ubuntu. It just happens to
|
||||
not be the distro I want.
|
||||
|
||||
However, I can ssh into my server with the Ubuntu VM and then I can click around
|
||||
in Weechat to my heart's content. I can also do weird builds with Nix and it
|
||||
just works. Neat.
|
||||
|
||||
I should probably figure out how hard it would be to get a NixOS-like
|
||||
environment in WSL, but WSL can't run systemd so I've been kinda avoiding it.
|
||||
Excising systemd from NixOS really defeats most of the point in my book. I may
|
||||
end up installing Nix on Alpine or something. IDK.
|
||||
|
||||
### PowerShell
|
||||
|
||||
They say you can learn a lot about the design of a command line interface by
|
||||
what commands are used to do things like change directory, list files in a
|
||||
directory and download files from the internet. In PowerShell these are
|
||||
`Get-ChildItem`, `Set-Location` and `Invoke-WebRequest`. However there are
|
||||
aliases for `ls`, `dir`, `cd` and `wget` (these aliases aren't always
|
||||
flag-compatible, so you may want to actually get used to doing things in the
|
||||
PowerShell way if you end up doing anything overly fancy).
|
||||
|
||||
Another annoying thing was that pressing Control-D on an empty prompt didn't end up closing the session. In order to do this you need to edit your shell profile file:
|
||||
|
||||
```
|
||||
PS C:\Users\xena> code $profile
|
||||
```
|
||||
|
||||
Then you add this to the .ps1 file:
|
||||
|
||||
```
|
||||
Set-PSReadlineOption -EditMode Emacs
|
||||
```
|
||||
|
||||
Save this file then close and re-open PowerShell.
|
||||
|
||||
If this was your first time editing your PowerShell config (like it was for me)
|
||||
you are going to have to mess with your
|
||||
[execution policy](https://www.mssqltips.com/sqlservertip/2702/setting-the-powershell-execution-policy/)
|
||||
to allow you to execute scrips on your local machine. I get the reason why they
|
||||
did this, PowerShell has a lot of...well...power over the system. Doing this
|
||||
must outright eliminate a lot of attack vectors without doing much on the
|
||||
admin's side. But this applies to your shell profile too. So you are going to
|
||||
need to make a choice as to what security level you want to have with PowerShell
|
||||
scripts. I personally went with `RemoteSigned`.
|
||||
|
||||
### Themes
|
||||
|
||||
I use stuff cribbed from [oh my fish](https://github.com/oh-my-fish/oh-my-fish)
|
||||
for my fish prompt. I googled "oh my powershell" and hoped I would get lucky
|
||||
with finding some nice batteries-included tools.
|
||||
[I got lucky](https://ohmyposh.dev/docs/installation/).
|
||||
|
||||
After looking through the options I saw a theme named `sorin` that looks like
|
||||
this:
|
||||
|
||||
![the sorin theme in action](https://cdn.christine.website/file/christine-static/blog/Screenshot+2021-03-03+231114.png)
|
||||
|
||||
### Project-local Dependencies
|
||||
|
||||
To get this I'd need to do everything in WSL and use Nix. VSCode even has some
|
||||
nice integration that makes this easy. I wish there was a more native option
|
||||
though.
|
||||
|
||||
## Things Windows Gets Really Right
|
||||
|
||||
The big thing that Windows gets really right as a developer is backwards
|
||||
compatibility. For better or worse I can install just about any program from
|
||||
the last 30 years of released software targeting windows and it will Just Work.
|
||||
|
||||
All of the games that I play natively target windows, and I don't have to hack
|
||||
at Steam's linux setup to get things like Sonic Adventure 2 working. All of the
|
||||
VR stuff I want to do will Just Work. All of the games I download will Just
|
||||
Work. I don't have to do the Proton rain dance. I don't have to play with GPU
|
||||
driver paths. I don't have to disable my compositor to get Factorio to launch.
|
||||
And most of all when I report a problem it's likely to actually be taken
|
||||
seriously instead of moaned at because I run a distribution without `/usr/lib`.
|
||||
|
||||
---
|
||||
|
||||
Overall, I think I can at least tolerate this development experience. It's not
|
||||
really the most ideal setup, but it does work and I can get things done with it.
|
||||
It makes me miss NixOS though. NixOS really does ruin your expectations of what
|
||||
a desktop operating system should be. It leaves you with kind of impossible
|
||||
standards, and it can be a bit hard to unlearn them.
|
||||
|
||||
A lot of the software I use is closed source proprietary software. I've tried to
|
||||
fight that battle before. I've given up. When it works, Linux on the desktop is
|
||||
a fantastic experience. Everything works together there. The system is a lot
|
||||
more cohesive compared to the "download random programs and hope for the best"
|
||||
strategy that you end up taking with Windows systems. It's hard to do the
|
||||
"download random programs and hope for the best" strategy with Linux on the
|
||||
desktop because there really isn't one Linux platform to target. There's 20 or
|
||||
something. This is an advantage sometimes, but is a huge pain other times.
|
||||
|
||||
The conclusion here is that there is no conclusion.
|
|
@ -9,15 +9,14 @@ fn main() -> Result<()> {
|
|||
.output()
|
||||
.unwrap();
|
||||
|
||||
if std::env::var("out").is_err() {
|
||||
println!("cargo:rustc-env=out=/yolo");
|
||||
}
|
||||
let out = std::env::var("out").unwrap_or("/fake".into());
|
||||
println!("cargo:rustc-env=out={}", out);
|
||||
|
||||
let git_hash = String::from_utf8(output.stdout).unwrap();
|
||||
println!(
|
||||
"cargo:rustc-env=GITHUB_SHA={}",
|
||||
if git_hash.as_str() == "" {
|
||||
env!("out").into()
|
||||
out.into()
|
||||
} else {
|
||||
git_hash
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue