-
-
Notifications
You must be signed in to change notification settings - Fork 146
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Make Firenvim work with a Windows browser and WSL neovim #839
Comments
For firenvim to work in WSL, you would need to run your browser in WSL. If you want to use Firenvim on a windows machine, you need to install neovim on windows. :) |
If I symlink the brave folder from Program Files to wsl home will that work? |
No, it won't, windows and WSL are separate and do not run the same programs. |
WSL is a virtualization layer that isolates processes from other layers. If you want processes to play together they have to be running in the same system. This is no different that almost any other virtualization or containerization system (VMWare, Vbox, Xen, Docker, Podman, etc.). You can interact through APIs provided by the hypervisor/virtualization/container system, but not directly with processes inside other layers. |
I'm closing this but feel free to ask more questions if you still don't understand what's going on/can't get firenvim to work on windows :) |
While that is true, there is a high degree of integration between wsl & windows, so it doesn't really matter if you're communicating with neovim over shared abstractions (e.g. tcp). While wsl is a traditional VM, windows & wsl do share the same host (i.e. network ports), & filesystems are accessible from either environment. (You can start apps in either environment from either system -- the app will run in the correct environment -- think "shebang processing on steroids".) Unless you're using os specific RPC, it may "just work". A working example is nvim (on wsl) embedded in vscode (on windows), using the VSCode Neo Vim extension. [NB: I'm not advocating to reopen, just sharing info.] |
@hwine Interesting, thanks for the info. For Firenvim to work with a WSL neovim and a Windows browser, we'd need to be able to do the following things:
Is all of this possible with WSL? |
I'm just a wsl & windows user, so there may be edge cases I'm missing
You can run
Yes. Very easy if you can support UNC paths, as the default wsl volume is mapped to
Yes, this works, although I don't know if there are buffering issues.
To be specific, it works on If you have specific tests you'd like me to run, Win10/wsl2 is my daily setup, so I could run them easily. |
@hwine Great, thanks a lot for your answers! I didn't know much about wsl, except for the architectural differences between wsl and wsl2 (running syscalls directly vs running linux in a VM) which made me assume that shared stdin/out wouldn't be possible. For Firenvim to work with a wsl neovim, I think we only need to update the firenvim installation script like this:
After that, Firenvim will probably just work. I don't have time to work on this at the moment (I'm currently working on #805 which is much harder than expected), so those who'd like to see wsl supported in the near future should work on it themselves and open a PR - I'll be very happy to review it and provide help/advice should this be necessary :). |
The following patch makes firenvim work on a windows firefox+wsl2 firenvim combination. I have yet to test other browsers/make sure that I haven't broken other types of setup. I'm uploading it here as I can't push from a windows machine. diff --git a/autoload/firenvim.vim b/autoload/firenvim.vim
index 1dff1aa..9b2db99 100644
--- a/autoload/firenvim.vim
+++ b/autoload/firenvim.vim
@@ -57,15 +57,61 @@ function! firenvim#press_keys(...) abort
call rpcnotify(firenvim#get_chan(), 'firenvim_press_keys', l:keys)
endfunction
+let s:is_wsl = !empty($WSLENV) || !empty($WSL_DISTRO_NAME) || !empty ($WSL_INTEROP)
+
+" Turns a wsl path (forward slashes) into a windows one (backslashes)
+function! s:to_windows_path(path) abort
+ if a:path[0] != '/'
+ return a:path
+ endif
+ let l:path_components = split(a:path, '/')
+ return join([toupper(l:path_components[1]) . ':'] + path_components[2:-1], '\')
+endfunction
+
+" Turns a windows path (backslashes) into a wsl one (forward slashes)
+function! s:to_wsl_path(path) abort
+ if a:path[0] == '/'
+ return a:path
+ endif
+ let l:path_components = split(a:path, '\\')
+ return join(['/mnt', tolower(path_components[0][0:-2])] + l:path_components[1:-1], '/')
+endfunction
+
+
" Simple helper to build the right path depending on the platform.
function! s:build_path(list) abort
let l:path_separator = '/'
if has('win32')
let l:path_separator = "\\"
endif
+ if s:is_wsl
+ let a:list[0] = s:to_wsl_path(a:list[0])
+ endif
return join(a:list, l:path_separator)
endfunction
+" Retrieves a windows env var from wsl. Retrieves a windows path (with
+" backslashes!)
+function! s:get_windows_env_path(env) abort
+ if has('win32')
+ let l:env = a:env
+ if l:env[0] == '%'
+ let l:env = '$' . l:env[1:-2]
+ endif
+ return expand(l:env)
+ endif
+ if s:is_wsl
+ let l:env = a:env
+ if l:env[0] == '$'
+ let l:env = '%' . l:env[1:-1] . '%'
+ endif
+ let l:cmd_output = system(['cmd.exe', '/c', 'echo', l:env])
+ return cmd_output[match(l:cmd_output, 'C:\\'):-3]
+ endif
+ throw "Used get_windows_env_path on non-windows platform!"
+endfunction
+
+
" Entry point of the vim-side of the extension.
" This function does the following things:
" - Get a security token from neovim's stdin
@@ -124,23 +170,27 @@ function! firenvim#run() abort
let l:chanid = stdioopen({ 'on_stdin': 'OnStdin' })
endfunction
+" Returns the name of the script that should be executed by the browser.
function! s:get_executable_name() abort
- if has('win32')
+ if has('win32') || s:is_wsl
return 'firenvim.bat'
endif
return 'firenvim'
endfunction
+" Returns the path of the directory in which firenvim will run when the
+" browser launches it.
+" On wsl, this is a path living on the linux side.
function! s:get_runtime_dir_path() abort
let l:xdg_runtime_dir = $XDG_RUNTIME_DIR
if l:xdg_runtime_dir ==# ''
- if has('win32')
- let l:xdg_runtime_dir = expand('$TEMP')
+ if has('win32') || s:is_wsl
+ let l:xdg_runtime_dir = s:get_windows_env_path('$TEMP')
if l:xdg_runtime_dir ==# ''
- let l:xdg_runtime_dir = expand('$TMP')
+ let l:xdg_runtime_dir = s:get_windows_env_path('$TMP')
endif
if l:xdg_runtime_dir ==# ''
- let l:xdg_runtime_dir = expand('$USERPROFILE')
+ let l:xdg_runtime_dir = s:get_windows_env_path('$USERPROFILE')
if l:xdg_runtime_dir ==# ''
let l:xdg_runtime_dir = fnamemodify(stdpath('data'), ':h')
else
@@ -157,9 +207,12 @@ function! s:get_runtime_dir_path() abort
return s:build_path([l:xdg_runtime_dir, 'firenvim'])
endfunction
+" Returns the directory in which the firenvim script is written.
function! s:get_data_dir_path() abort
let l:xdg_data_home = $XDG_DATA_HOME
- if l:xdg_data_home ==# ''
+ if s:is_wsl
+ let l:xdg_data_home = s:get_windows_env_path('%LOCALAPPDATA%')
+ elseif l:xdg_data_home ==# ''
let l:xdg_data_home = fnamemodify(stdpath('data'), ':h')
endif
return s:build_path([l:xdg_data_home, 'firenvim'])
@@ -171,14 +224,17 @@ function! s:firefox_config_exists() abort
let l:p = [$HOME, 'Library', 'Application Support', 'Mozilla']
elseif has('win32')
let l:p = [$HOME, 'AppData', 'Roaming', 'Mozilla', 'Firefox']
- end
+ elseif s:is_wsl
+ let l:p = [s:get_windows_env_path('%APPDATA%'), 'Mozilla', 'Firefox']
+ endif
+ echo l:p
return isdirectory(s:build_path(l:p))
endfunction
function! s:get_firefox_manifest_dir_path() abort
if has('mac')
return s:build_path([$HOME, 'Library', 'Application Support', 'Mozilla', 'NativeMessagingHosts'])
- elseif has('win32')
+ elseif has('win32') || s:is_wsl
return s:get_data_dir_path()
end
return s:build_path([$HOME, '.mozilla', 'native-messaging-hosts'])
@@ -190,6 +246,8 @@ function! s:brave_config_exists() abort
let l:p = [$HOME, 'Library', 'Application Support', 'BraveSoftware']
elseif has('win32')
let l:p = [$HOME, 'AppData', 'Local', 'BraveSoftware']
+ elseif s:is_wsl
+ let l:p = [s:get_windows_env_path('%LOCALAPPDATA%'), 'BraveSoftware']
elseif !empty($XDG_CONFIG_HOME)
let l:p = [$XDG_CONFIG_HOME, 'BraveSoftware']
end
@@ -202,6 +260,8 @@ function! s:opera_config_exists() abort
let l:p = [$HOME, 'Library', 'Application Support', 'com.operasoftware.Opera']
elseif has('win32')
let l:p = [$HOME, 'AppData', 'Local', 'Opera Software']
+ elseif s:is_wsl
+ let l:p = [s:get_windows_env_path('%LOCALAPPDATA%'), 'Opera Software']
elseif !empty($XDG_CONFIG_HOME)
let l:p = [$XDG_CONFIG_HOME, 'opera']
end
@@ -214,6 +274,8 @@ function! s:vivaldi_config_exists() abort
let l:p = [$HOME, 'Library', 'Application Support', 'Vivaldi']
elseif has('win32')
let l:p = [$HOME, 'AppData', 'Local', 'Vivaldi']
+ elseif s:is_wsl
+ let l:p = [s:get_windows_env_path('%LOCALAPPDATA%'), 'Vivaldi']
elseif !empty($XDG_CONFIG_HOME)
let l:p = [$XDG_CONFIG_HOME, 'vivaldi']
end
@@ -226,6 +288,8 @@ function! s:chrome_config_exists() abort
let l:p = [$HOME, 'Library', 'Application Support', 'Google', 'Chrome']
elseif has('win32')
let l:p = [$HOME, 'AppData', 'Local', 'Google', 'Chrome']
+ elseif s:is_wsl
+ let l:p = [s:get_windows_env_path('%LOCALAPPDATA%'), 'Google', 'Chrome']
elseif !empty($XDG_CONFIG_HOME)
let l:p = [$XDG_CONFIG_HOME, 'google-chrome']
end
@@ -243,7 +307,7 @@ endfunction
function! s:get_chrome_manifest_dir_path() abort
if has('mac')
return s:build_path([$HOME, 'Library', 'Application Support', 'Google', 'Chrome', 'NativeMessagingHosts'])
- elseif has('win32')
+ elseif has('win32') || s:is_wsl
return s:get_data_dir_path()
end
if !empty($XDG_CONFIG_HOME)
@@ -255,7 +319,7 @@ endfunction
function! s:get_chrome_dev_manifest_dir_path() abort
if has('mac')
throw 'No chrome dev on mac.'
- elseif has('win32')
+ elseif has('win32') || s:is_wsl
throw 'No chrome dev on win32.'
end
if !empty($XDG_CONFIG_HOME)
@@ -267,7 +331,7 @@ endfunction
function! s:get_brave_manifest_dir_path() abort
if has('mac')
return s:get_chrome_manifest_dir_path()
- elseif has('win32')
+ elseif has('win32') || s:is_wsl
return s:get_chrome_manifest_dir_path()
end
if !empty($XDG_CONFIG_HOME)
@@ -281,6 +345,8 @@ function! s:canary_config_exists() abort
let l:p = [$HOME, 'Library', 'Application Support', 'Google', 'Chrome Canary']
elseif has('win32')
let l:p = [$HOME, 'AppData', 'Local', 'Google', 'Chrome SxS']
+ elseif s:is_wsl
+ let l:p = [s:get_windows_env_path('%LOCALAPPDATA%'), 'Google', 'Chrome SxS']
else
" Chrome canary doesn't exist on linux
return v:false
@@ -291,19 +357,20 @@ endfunction
function! s:get_canary_manifest_dir_path() abort
if has('mac')
return s:build_path([$HOME, 'Library', 'Application Support', 'Google', 'Chrome Canary', 'NativeMessagingHosts'])
- elseif has('win32')
+ elseif has('win32') || s:is_wsl
return s:get_data_dir_path()
end
throw "Chrome Canary doesn't exist on Linux"
endfunction
-
function! s:chromium_config_exists() abort
let l:p = [$HOME, '.config', 'chromium']
if has('mac')
let l:p = [$HOME, 'Library', 'Application Support', 'Chromium']
elseif has('win32')
let l:p = [$HOME, 'AppData', 'Local', 'Chromium']
+ elseif s:is_wsl
+ let l:p = [s:get_windows_env_path('%LOCALAPPDATA%'), 'Chromium']
end
if !empty($XDG_CONFIG_HOME)
let l:p = [$XDG_CONFIG_HOME, 'chromium', 'NativeMessagingHosts']
@@ -314,7 +381,7 @@ endfunction
function! s:get_chromium_manifest_dir_path() abort
if has('mac')
return s:build_path([$HOME, 'Library', 'Application Support', 'Chromium', 'NativeMessagingHosts'])
- elseif has('win32')
+ elseif has('win32') || s:is_wsl
return s:get_data_dir_path()
end
if !empty($XDG_CONFIG_HOME)
@@ -372,12 +439,17 @@ function! s:get_progpath() abort
endfunction
function! s:get_executable_content(data_dir, prolog) abort
- if has('win32')
+ if has('win32') || s:is_wsl
+ let l:wsl_prefix = ''
+ if s:is_wsl
+ let l:wsl_prefix = 'wsl'
+ endif
+ let l:dir = s:to_windows_path(a:data_dir)
return "@echo off\r\n" .
- \ "mkdir \"" . a:data_dir . "\" 2>nul\r\n" .
- \ "cd \"" . a:data_dir . "\"\r\n" .
+ \ "mkdir \"" . l:dir . "\" 2>nul\r\n" .
+ \ "cd \"" . l:dir . "\"\r\n" .
\ a:prolog . "\r\n" .
- \ "\"" . s:get_progpath() . "\" --headless --cmd \"let g:started_by_firenvim = v:true\" -c \"call firenvim#run()\"\r\n"
+ \ l:wsl_prefix . ' ' . "\"" . s:get_progpath() . "\" --headless --cmd \"let g:started_by_firenvim = v:true\" -c \"call firenvim#run()\"\r\n"
endif
return "#!/bin/sh\n" .
\ 'mkdir -p ' . a:data_dir . "\n" .
@@ -422,7 +494,7 @@ function! s:key_to_ps1_str(key, manifest_path) abort
" Then, assign a value to it
return l:ps1_content . "\nSet-Item -Path \"" .
\ a:key .
- \ '\" -Value "' . a:manifest_path . '"'
+ \ '\" -Value "' . s:to_windows_path(a:manifest_path) . '"'
endfunction
function! s:get_browser_configuration() abort
@@ -520,11 +592,18 @@ function! firenvim#install(...) abort
" Decide where the script responsible for starting neovim should be
let l:data_dir = s:get_data_dir_path()
let l:execute_nvim_path = s:build_path([l:data_dir, s:get_executable_name()])
+
" Write said script to said path
let l:execute_nvim = s:get_executable_content(s:get_runtime_dir_path(), l:script_prolog)
call mkdir(l:data_dir, 'p', 0700)
+ if s:is_wsl
+ let l:execute_nvim_path = s:to_wsl_path(l:execute_nvim_path)
+ endif
call writefile(split(l:execute_nvim, "\n"), l:execute_nvim_path)
+ if s:is_wsl
+ let l:execute_nvim_path = s:to_windows_path(l:execute_nvim_path)
+ endif
call setfperm(l:execute_nvim_path, 'rwx------')
let l:browsers = s:get_browser_configuration()
@@ -546,7 +625,7 @@ function! firenvim#install(...) abort
continue
endtry
- if has('win32')
+ if has('win32') || s:is_wsl
let l:manifest_path = s:build_path([l:manifest_dir_path, 'firenvim-' . l:name . '.json'])
endif
@@ -556,7 +635,7 @@ function! firenvim#install(...) abort
echo 'Installed native manifest for ' . l:name . '.'
- if has('win32')
+ if has('win32') || s:is_wsl
" On windows, also create a registry key. We do this
" by writing a powershell script to a file and
" executing it.
@@ -566,7 +645,7 @@ function! firenvim#install(...) abort
echo 'Creating registry key for ' . l:name . '. This may take a while. Script: ' . l:ps1_path
call writefile(split(l:ps1_content, "\n"), l:ps1_path)
call setfperm(l:ps1_path, 'rwx------')
- let o = system(['powershell', '-Command', '-'], readfile(l:ps1_path))
+ let o = system(['powershell.exe', '-Command', '-'], readfile(l:ps1_path))
if v:shell_error
echo o
endif
@@ -598,10 +677,10 @@ function! firenvim#uninstall() abort
let l:manifest_path = s:build_path([l:manifest_dir_path, 'firenvim-' . l:name . '.json'])
endif
- if has('win32')
+ if has('win32') || s:is_wsl
echo 'Removing registry key for ' . l:name . '. This may take a while.'
let l:ps1_content = 'Remove-Item -Path "' . l:cur_browser['registry_key'] . '" -Recurse'
- let o = system(['powershell', '-Command', '-'], [l:ps1_content])
+ let o = system(['powershell.exe', '-Command', '-'], [l:ps1_content])
if v:shell_error
echo o
endif |
Now implemented in master - update the firenvim plugin and run |
I am unable to get this to work with WSL, is there a workaround or is there no support
The text was updated successfully, but these errors were encountered: