Last active
July 9, 2024 15:54
-
-
Save kamack38/a1ec169bde3051873b8cb18be2a7c320 to your computer and use it in GitHub Desktop.
Portable Neovim using Neovide with Git and Font added to PATH on Windows
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <windows.h> | |
#include <iostream> | |
#include <string> | |
#include <vector> | |
bool LoadCustomFont(const std::string &fontPath) { | |
// Load the font from the specified file path | |
int numFontsAdded = AddFontResourceA(fontPath.c_str()); | |
if (numFontsAdded > 0) { | |
return true; | |
} else { | |
std::cerr << "Failed to load font from " << fontPath << std::endl; | |
return false; | |
} | |
} | |
void UnloadCustomFont(const std::string &fontPath) { | |
// Remove the font from the system font table | |
RemoveFontResourceA(fontPath.c_str()); | |
} | |
bool LoadFonts(const std::vector<std::string> &fonts, const std::string parentPath) { | |
int index = 0; | |
for (; index < fonts.size(); ++index) { | |
if (!LoadCustomFont(parentPath + fonts[index])) { | |
for (--index; index >= 0; --index) { | |
UnloadCustomFont(parentPath + fonts[index]); | |
} | |
return false; | |
} | |
} | |
return true; | |
} | |
void UnloadFonts(const std::vector<std::string> &fonts, const std::string parentPath) { | |
for (auto font : fonts) { | |
UnloadCustomFont(parentPath + font); | |
} | |
} | |
bool SetEnvVariable(const char *name, const char *value) { | |
if (SetEnvironmentVariableA(name, value)) { | |
return true; | |
} else { | |
std::cerr << "Failed to set environment variable " << name << std::endl; | |
return false; | |
} | |
} | |
bool RunExecutable(const std::string &executablePath, const std::string &arguments) { | |
STARTUPINFOA si; | |
PROCESS_INFORMATION pi; | |
ZeroMemory(&si, sizeof(si)); | |
si.cb = sizeof(si); | |
ZeroMemory(&pi, sizeof(pi)); | |
// Construct the full command line with arguments | |
std::string fullCommand = executablePath + " " + arguments; | |
// Start the child process. | |
if (!CreateProcessA(NULL, // No module name (use command line) | |
const_cast<char *>(fullCommand.c_str()), // Command line | |
NULL, // Process handle not inheritable | |
NULL, // Thread handle not inheritable | |
FALSE, // Set handle inheritance to FALSE | |
0, // No creation flags | |
NULL, // Use parent's environment block | |
NULL, // Use parent's starting directory | |
&si, // Pointer to STARTUPINFO structure | |
&pi) // Pointer to PROCESS_INFORMATION structure | |
) { | |
std::cerr << "CreateProcess failed: " << GetLastError() << std::endl; | |
return false; | |
} | |
// Wait until child process exits. | |
WaitForSingleObject(pi.hProcess, INFINITE); | |
// Close process and thread handles. | |
CloseHandle(pi.hProcess); | |
CloseHandle(pi.hThread); | |
return true; | |
} | |
std::string GetExecutablePath() { | |
char buffer[MAX_PATH]; | |
GetModuleFileNameA(NULL, buffer, MAX_PATH); | |
std::string::size_type pos = std::string(buffer).find_last_of("\\/"); | |
return std::string(buffer).substr(0, pos); | |
} | |
inline void HideConsole() { ::ShowWindow(::GetConsoleWindow(), SW_HIDE); } | |
int main(int argc, char *argv[]) { | |
HideConsole(); | |
std::string exePath = GetExecutablePath(); | |
// Construct paths relative to the executable path | |
std::string fontsDir = exePath + "\\fonts\\"; | |
std::string neovidePath = exePath + "\\neovide.exe"; | |
std::string xdgConfigHome = exePath + "\\config"; | |
std::vector<std::string> fonts = { | |
"FiraCodeNerdFontMono-Medium.ttf", "FiraCodeNerdFontMono-Bold.ttf", | |
"FiraCodeNerdFontMono-Light.ttf", "FiraCodeNerdFontMono-SemiBold.ttf", | |
"FiraCodeNerdFontMono-Regular.ttf"}; | |
std::vector<std::string> paths = {"\\git\\bin", "\\nvim\\bin"}; | |
// Load the custom font | |
if (!LoadFonts(fonts, fontsDir)) { | |
return 1; | |
} | |
// Set the PATH environment variable | |
char currentPath[32767]; | |
if (GetEnvironmentVariableA("PATH", currentPath, sizeof(currentPath)) > 0) { | |
std::string newPath = std::string(currentPath); | |
for (auto path : paths) { | |
newPath += (";" + exePath + path); | |
} | |
if (!SetEnvVariable("PATH", newPath.c_str())) { | |
std::cerr << "Could not set PATH"; | |
UnloadFonts(fonts, fontsDir); | |
return 1; | |
} | |
} else { | |
std::cerr << "Failed to get current PATH"; | |
UnloadFonts(fonts, fontsDir); | |
return 1; | |
} | |
// Set the XDG_CONFIG_HOME environment variable | |
if (!SetEnvVariable("XDG_CONFIG_HOME", xdgConfigHome.c_str())) { | |
std::cerr << "Could not set XDG_CONFIG_HOME variable"; | |
UnloadFonts(fonts, fontsDir); | |
return 1; | |
} | |
// Pass all passed arguments to Neovide | |
std::string neovideArguments = ""; | |
for (int i = 1; i < argc; ++i) { // Start from 1 to skip the first argument (program name) | |
neovideArguments += " " + std::string(argv[i]); | |
} | |
// Run the Neovide executable | |
if (!RunExecutable(neovidePath, neovideArguments)) { | |
UnloadFonts(fonts, fontsDir); | |
return 1; | |
} | |
// Unload the custom fonts | |
UnloadFonts(fonts, fontsDir); | |
return 0; | |
} |
Dependencies:
Useful links
Structure:
prog.exe
neovide.exe
π fonts
β FiraCodeNerdFontMono-Bold.ttf
β FiraCodeNerdFontMono-Light.ttf
β FiraCodeNerdFontMono-Medium.ttf
β FiraCodeNerdFontMono-Regular.ttf
β FiraCodeNerdFontMono-Retina.ttf
β FiraCodeNerdFontMono-SemiBold.ttf
π config
π git
π nvim
To use FiraCode as your font set:
vim.o.guifont = "FiraCode Nerd Font Mono:h12"
TODO:
- Argument passing
- Font loading
- Setting PATH
- Set Neovim cache dir and all other directories to contain the application.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
To compile run:
(Tested with MingW installed via chocolatey)
When compiled, it allows creating a portable Neovim installation.
You can drag and drop a file on the prog.exe because it passes all commandline arguments to Neovide which then passes them to Neovim.