Setting a default editor in Microsoft Windows

Notepad is the default text editor on Windows since the first release.

Unfortunately, it did not get updated with the rest of the operating systems. Just very recently some minor features, like support for unix line endings, were finally added.

There have been different hacks and techniques for replacing the notepad executable with a more advanced editor, but they always had the disadvantage that they put the system in an "unspecified" state. In the best case, a Windows Update would reset the system to its original state. In the worst case, the different behavior between notepad and the new text editor might screw something up.

Windows Explorer also has the disadvantage of not being able to associate programs for opening files without extensions, and always asking how to open them. This is especially unfortunate for files like README and LICENSE or configuration files used by command line applications.

It might not be the most well-known feature of Windows, but it does actually offers customization points similar to update-alternatives provided by Debian and other GNU/Linux systems. The disadvantage of those customization points is that there is no GUI setting, are hardly documented, and you need to edit the registry.

The registry key HKEY_CLASSES_ROOT\Unknown\shell is responsible for files that have no associations. All files that Windows does not know how to open, as .bashrc, .gitignore, .doc, .docx and so on, are categorized as unknown until opened and associated with a program the first time.

The key HKEY_CLASSES_ROOT\txtfile is for files registered as text files. For example, those ending in .txt, but other file endings, like .log and .scp, are registered as text files too.

As there are so many different file extensions associated with textual files, it can be very practical to have a text editor opening by default every file.

Long story short, this is how it can be accomplished:

$editor = "`"C:\Program Files\Notepad++\notepad++.exe`""
# $editor = "`"C:\Program Files (x86)\Vim\vim81\gvim.exe`""

# register and set editor for unknown files
$key = "Registry::HKEY_CLASSES_ROOT\Unknown\shell"
If (!(Test-Path $key)) {
  New-Item "$key" -Force
}
Set-ItemProperty -Path "$key" -name '(Default)' -Value "editor"

$key = "Registry::HKEY_CLASSES_ROOT\Unknown\shell\editor\command"
If (!(Test-Path $key)) {
  New-Item "$key" -Force
}
Set-ItemProperty -Path "$key" -name '(Default)' -Value "$editor `"%1`""

# register editor for known textual files
$key = "Registry::HKEY_CLASSES_ROOT\Unknown\shell\Open\command"
If (!(Test-Path $key)) {
  New-Item "$key" -Force
}
Set-ItemProperty -Path "$key"  -name '(Default)' -Value "$editor `"%1`""

# set default editor for already known extual files
$filetypes = @("txtfile", "inifile", "xmlfile")
foreach ($filetype in $filetypes) {
  $key = (Join-Path (Join-Path Registry::HKEY_CLASSES_ROOT $filetype) shell\open\command)
  If (!(Test-Path $key)) {
    New-Item "$key" -Force
  }
  Set-ItemProperty -Path "$key"  -name '(Default)' -Value "$editor `"%1`""
}

It is also possible to add a context menu to explorer. Notice that both notepad++ and vim setups already add a menu entry in explorer, so for those programs, it’s not necessary.

# apparently "*" gets expanded, and "`*" does not escape..., thus use a different syntax
$key = (get-item Registry::HKEY_CLASSES_ROOT).CreateSubKey("*\shell\Open with text editor\command")
$key.SetValue('', "$editor `"%1`"");

# in case there is a nice icon
$key = (get-item Registry::HKEY_CLASSES_ROOT).OpenSubKey("*\shell\Open with text editor", $true)
$key.SetValue('Icon', "$editor");

For those who use Run Command (through Win+R) for executing programs, here is how to register editor as a new command, without creating an editor executable and placing it somewhere in PATH. It does not add the command to the cmd or PowerShell environments. This is unfortunate, since it adds an inconsistency, but also practical in case you use cygwin or WSL.

# add editor to "run command"
$key = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\editor.exe"
If (!(Test-Path $key)) {
  New-Item "$key" -Force
}
Set-ItemProperty -Path "$key"  -name '(Default)' -Value "$editor"

As an example, I’ve used notepad++, of course, other editors, and even command line editors like nano, vim or emacs, can be set exactly the same way.

Those settings also do apply to every user. This is especially useful when installing or configuring a new system. The normal user and the administrator account will have the same default settings.

Of course, a single user can still define what programs to execute when opening specific files unless that file has no extension. This is the single drawback I experienced since instead of asking, the file will be opened with a program that may be the user does not want to use. Other than that, everything works as expected.