Skip to content

Commit 7ac805c

Browse files
authored
Merge pull request #2942 from daxgames/cmder4win
Cmder for Windows - Add `Bash`, `Powershell`, `mintty`.
2 parents 15d5618 + c1bbc46 commit 7ac805c

File tree

7 files changed

+205
-88
lines changed

7 files changed

+205
-88
lines changed

.github/workflows/build.yml

+21
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,27 @@ jobs:
5252
working-directory: scripts
5353
run: .\pack.ps1 -verbose -terminal all
5454

55+
- name: Upload artifact (cmder_win_mini.zip)
56+
uses: actions/upload-artifact@v3
57+
with:
58+
path: build/cmder_win_mini.zip
59+
name: cmder_win_mini.zip
60+
if-no-files-found: error
61+
62+
- name: Upload artifact (cmder_win.7z)
63+
uses: actions/upload-artifact@v3
64+
with:
65+
path: build/cmder_win.7z
66+
name: cmder_win.7z
67+
if-no-files-found: error
68+
69+
- name: Upload artifact (cmder_win.zip)
70+
uses: actions/upload-artifact@v3
71+
with:
72+
path: build/cmder_win.zip
73+
name: cmder_win.zip
74+
if-no-files-found: error
75+
5576
- name: Upload artifact (cmder_wt.zip)
5677
uses: actions/upload-artifact@v3
5778
with:

CHANGELOG.md

+6
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,12 @@
66

77
- Fixes #2940
88

9+
### Adds
10+
11+
- Cmder for Windows
12+
- Uses Windows and Git for Windows Native Terminals.
13+
- Does not contain a terminal emulator like ConEmu or Windows Terminal.
14+
915
## [1.3.20](https://github.com/cmderdev/cmder/tree/v1.3.20) (2022-03-18)
1016

1117
### Changes

launcher/CmderLauncher.vcxproj

+3
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,9 @@
188188
<ItemGroup>
189189
<ClCompile Include="src\CmderLauncher.cpp" />
190190
</ItemGroup>
191+
<ItemGroup>
192+
<Image Include="..\icons\cmder.ico" />
193+
</ItemGroup>
191194
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
192195
<ImportGroup Label="ExtensionTargets">
193196
</ImportGroup>

launcher/src/CmderLauncher.cpp

+120-50
Original file line numberDiff line numberDiff line change
@@ -107,9 +107,9 @@ bool FileExists(const wchar_t * filePath)
107107

108108
void StartCmder(std::wstring path = L"", bool is_single_mode = false, std::wstring taskName = L"", std::wstring title = L"", std::wstring iconPath = L"", std::wstring cfgRoot = L"", bool use_user_cfg = true, std::wstring conemu_args = L"")
109109
{
110-
#if USE_TASKBAR_API
111-
wchar_t appId[MAX_PATH] = { 0 };
112-
#endif
110+
#if USE_TASKBAR_API
111+
wchar_t appId[MAX_PATH] = { 0 };
112+
#endif
113113
wchar_t exeDir[MAX_PATH] = { 0 };
114114
wchar_t icoPath[MAX_PATH] = { 0 };
115115
wchar_t cfgPath[MAX_PATH] = { 0 };
@@ -131,8 +131,17 @@ void StartCmder(std::wstring path = L"", bool is_single_mode = false, std::wstr
131131
wchar_t windowsTerminalDir[MAX_PATH] = { 0 };
132132
wchar_t conEmuDir[MAX_PATH] = { 0 };
133133
wchar_t winDir[MAX_PATH] = { 0 };
134-
wchar_t emulatorPath[MAX_PATH] = { 0 };
135-
134+
wchar_t vendorDir[MAX_PATH] = { 0 };
135+
wchar_t initCmd[MAX_PATH] = { 0 };
136+
wchar_t initPowerShell[MAX_PATH] = { 0 };
137+
wchar_t initBash[MAX_PATH] = { 0 };
138+
wchar_t initMintty[MAX_PATH] = { 0 };
139+
wchar_t vendoredGit[MAX_PATH] = { 0 };
140+
wchar_t amdx64Git[MAX_PATH] = { 0 };
141+
wchar_t x86Git[MAX_PATH] = { 0 };
142+
wchar_t programFiles[MAX_PATH] = { 0 };
143+
wchar_t programFilesX86[MAX_PATH] = { 0 };
144+
wchar_t minTTYPath[MAX_PATH] = { 0 };
136145

137146
std::wstring cmderStart = path;
138147
std::wstring cmderTask = taskName;
@@ -144,9 +153,9 @@ void StartCmder(std::wstring path = L"", bool is_single_mode = false, std::wstr
144153

145154
GetModuleFileName(NULL, exeDir, sizeof(exeDir));
146155

147-
#if USE_TASKBAR_API
148-
wcscpy_s(appId, exeDir);
149-
#endif
156+
#if USE_TASKBAR_API
157+
wcscpy_s(appId, exeDir);
158+
#endif
150159

151160
PathRemoveFileSpec(exeDir);
152161

@@ -255,8 +264,9 @@ void StartCmder(std::wstring path = L"", bool is_single_mode = false, std::wstr
255264
}
256265
}
257266

258-
PathCombine(windowsTerminalDir, exeDir, L"vendor\\windows-terminal");
259-
PathCombine(conEmuDir, exeDir, L"vendor\\conemu-maximus5");
267+
PathCombine(vendorDir, exeDir, L"vendor");
268+
PathCombine(windowsTerminalDir, vendorDir, L"windows-terminal");
269+
PathCombine(conEmuDir, vendorDir, L"conemu-maximus5");
260270
GetEnvironmentVariable(L"WINDIR", winDir, MAX_PATH);
261271

262272
if (PathFileExists(windowsTerminalDir))
@@ -319,7 +329,7 @@ void StartCmder(std::wstring path = L"", bool is_single_mode = false, std::wstr
319329
{
320330
if (!CopyFile(cpuCfgPath, cfgPath, FALSE))
321331
{
322-
if (PathFileExists(windowsTerminalDir)) {
332+
if (PathFileExists(windowsTerminalDir)) {
323333
MessageBox(NULL,
324334
(GetLastError() == ERROR_ACCESS_DENIED)
325335
? L"Failed to copy config/windows_terminal_%COMPUTERNAME%_settings.json file to vendor/windows-terminal/settings/settings.json! Access Denied."
@@ -346,7 +356,8 @@ void StartCmder(std::wstring path = L"", bool is_single_mode = false, std::wstr
346356
{
347357
if (!CopyFile(cfgPath, userCfgPath, FALSE))
348358
{
349-
if (PathFileExists(windowsTerminalDir)) {
359+
if (PathFileExists(windowsTerminalDir))
360+
{
350361
MessageBox(NULL,
351362
(GetLastError() == ERROR_ACCESS_DENIED)
352363
? L"Failed to copy vendor/windows-terminal/settings/settings.json file to config/windows_terminal_settings.json! Access Denied."
@@ -367,7 +378,8 @@ void StartCmder(std::wstring path = L"", bool is_single_mode = false, std::wstr
367378
{
368379
if (!CopyFile(userCfgPath, cfgPath, FALSE))
369380
{
370-
if (PathFileExists(windowsTerminalDir)) {
381+
if (PathFileExists(windowsTerminalDir))
382+
{
371383
MessageBox(NULL,
372384
(GetLastError() == ERROR_ACCESS_DENIED)
373385
? L"Failed to copy config/user_windows_terminal_settings.json file to vendor/windows-terminal/settings/settings.json! Access Denied."
@@ -395,7 +407,8 @@ void StartCmder(std::wstring path = L"", bool is_single_mode = false, std::wstr
395407
{
396408
if (!CopyFile(cfgPath, userCfgPath, FALSE))
397409
{
398-
if (PathFileExists(windowsTerminalDir)) {
410+
if (PathFileExists(windowsTerminalDir))
411+
{
399412
MessageBox(NULL,
400413
(GetLastError() == ERROR_ACCESS_DENIED)
401414
? L"Failed to copy vendor/windows-terminal/settings/settings.json file to config/user_windows_terminal_settings.json! Access Denied."
@@ -415,7 +428,8 @@ void StartCmder(std::wstring path = L"", bool is_single_mode = false, std::wstr
415428
{
416429
if (!CopyFile(defaultCfgPath, cfgPath, FALSE))
417430
{
418-
if (PathFileExists(windowsTerminalDir)) {
431+
if (PathFileExists(windowsTerminalDir))
432+
{
419433
MessageBox(NULL,
420434
(GetLastError() == ERROR_ACCESS_DENIED)
421435
? L"Failed to copy vendor/windows-terminal_default_settings_settings.json file to vendor/windows-terminal/settings/settings.json! Access Denied."
@@ -437,7 +451,7 @@ void StartCmder(std::wstring path = L"", bool is_single_mode = false, std::wstr
437451
{
438452
MessageBox(NULL,
439453
(GetLastError() == ERROR_ACCESS_DENIED)
440-
? L"Failed to copy vendor/ConEmu.xml.default file to vendor/conemu-maximus5/ConEmu.xml! Access Denied."
454+
? L"Failed to copy vendor/ConEmu.xml.default file to vendor/conemu-maximus5/ConEmu.xml! Access Denied."
441455
: L"Failed to copy vendor/ConEmu.xml.default file to vendor/conemu-maximus5/ConEmu.xml!", MB_TITLE, MB_ICONSTOP);
442456
exit(1);
443457
}
@@ -446,7 +460,8 @@ void StartCmder(std::wstring path = L"", bool is_single_mode = false, std::wstr
446460
{
447461
if (!CopyFile(cfgPath, userCfgPath, FALSE))
448462
{
449-
if (PathFileExists(windowsTerminalDir)) {
463+
if (PathFileExists(windowsTerminalDir))
464+
{
450465
MessageBox(NULL,
451466
(GetLastError() == ERROR_ACCESS_DENIED)
452467
? L"Failed to copy vendor/windows-terminal/settings/settings.json file to config/user_windows_terminal_settings_settings.json! Access Denied."
@@ -469,7 +484,8 @@ void StartCmder(std::wstring path = L"", bool is_single_mode = false, std::wstr
469484
{
470485
if ( ! CopyFile(defaultCfgPath, userCfgPath, FALSE))
471486
{
472-
if (PathFileExists(windowsTerminalDir)) {
487+
if (PathFileExists(windowsTerminalDir))
488+
{
473489
MessageBox(NULL,
474490
(GetLastError() == ERROR_ACCESS_DENIED)
475491
? L"Failed to copy vendor/windows-terminal_default_settings_settings.json file to [user specified path]/config/user_windows_terminal_settings.json! Access Denied."
@@ -488,22 +504,50 @@ void StartCmder(std::wstring path = L"", bool is_single_mode = false, std::wstr
488504
PathCombine(userConEmuCfgPath, userConfigDirPath, L"user-ConEmu.xml");
489505
}
490506

507+
GetEnvironmentVariable(L"ProgramFiles", programFiles, MAX_PATH);
508+
GetEnvironmentVariable(L"ProgramFiles(x86)", programFilesX86, MAX_PATH);
509+
510+
PathCombine(vendoredGit, vendorDir, L"git-for-windows");
511+
PathCombine(amdx64Git, programFiles, L"Git");
512+
PathCombine(x86Git, programFilesX86, L"Git");
513+
491514
SYSTEM_INFO sysInfo;
492515
GetNativeSystemInfo(&sysInfo);
493-
if (PathFileExists(windowsTerminalDir)) {
516+
if (PathFileExists(windowsTerminalDir))
517+
{
494518
PathCombine(terminalPath, exeDir, L"vendor\\windows-terminal\\WindowsTerminal.exe");
495519
}
496520
else if (PathFileExists(conEmuDir))
497521
{
522+
swprintf_s(args, L"%s /Icon \"%s\"", args, icoPath);
523+
swprintf_s(args, L"%s /title \"%s\"", args, cmderTitle.c_str());
498524
PathCombine(terminalPath, exeDir, L"vendor\\conemu-maximus5\\ConEmu64.exe");
499525
}
500526
else
501527
{
502528
PathCombine(terminalPath, winDir, L"system32\\cmd.exe");
503-
}
504529

505-
if (!PathFileExists(windowsTerminalDir)) {
506-
swprintf_s(args, L"%s /Icon \"%s\"", args, icoPath);
530+
if (streqi(cmderTask.c_str(), L"powershell"))
531+
{
532+
PathCombine(terminalPath, winDir, L"System32\\WindowsPowerShell\\v1.0\\powershell.exe");
533+
}
534+
/*
535+
else if (streqi(cmderTask.c_str(), L"mintty"))
536+
{
537+
if (PathFileExists(vendoredGit))
538+
{
539+
PathCombine(terminalPath, vendoredGit, L"git-bash.exe");
540+
}
541+
else if (PathFileExists(amdx64Git))
542+
{
543+
PathCombine(terminalPath, amdx64Git, L"git-bash.exe");
544+
}
545+
else if (PathFileExists(x86Git))
546+
{
547+
PathCombine(terminalPath, x86Git, L"git-bash.exe");
548+
}
549+
}
550+
*/
507551
}
508552

509553
if (!streqi(cmderStart.c_str(), L""))
@@ -524,13 +568,6 @@ void StartCmder(std::wstring path = L"", bool is_single_mode = false, std::wstr
524568
}
525569
}
526570

527-
if (!streqi(cmderTitle.c_str(), L""))
528-
{
529-
if (!PathFileExists(windowsTerminalDir)) {
530-
swprintf_s(args, L"%s /title \"%s\"", args, cmderTitle.c_str());
531-
}
532-
}
533-
534571
if (cfgRoot.length() != 0)
535572
{
536573
if (!PathFileExists(windowsTerminalDir)) {
@@ -546,6 +583,11 @@ void StartCmder(std::wstring path = L"", bool is_single_mode = false, std::wstr
546583
// The `/run` arg and its value MUST be the last arg of ConEmu
547584
// see : https://conemu.github.io/en/ConEmuArgs.html
548585
// > This must be the last used switch (excepting -new_console and -cur_console)
586+
PathCombine(initCmd, vendorDir, L"init.bat");
587+
PathCombine(initPowerShell, vendorDir, L"profile.ps1");
588+
PathCombine(initBash, vendorDir, L"start_git_bash.cmd");
589+
PathCombine(initMintty, vendorDir, L"start_git_mintty.cmd");
590+
549591
if (!streqi(cmderTask.c_str(), L""))
550592
{
551593
if (PathFileExists(windowsTerminalDir)) {
@@ -557,7 +599,22 @@ void StartCmder(std::wstring path = L"", bool is_single_mode = false, std::wstr
557599
}
558600
else
559601
{
560-
swprintf_s(args, L"%s %s", args, cmderTask.c_str());
602+
if (streqi(cmderTask.c_str(), L"powershell"))
603+
{
604+
swprintf_s(args, L"%s -ExecutionPolicy Bypass -NoLogo -NoProfile -NoExit -Command \"Invoke-Expression 'Import-Module ''%s'''\"", args, initPowerShell);
605+
}
606+
else if (streqi(cmderTask.c_str(), L"bash"))
607+
{
608+
swprintf_s(args, L"%s /c \"%s\"", args, initBash);
609+
}
610+
else if (streqi(cmderTask.c_str(), L"mintty"))
611+
{
612+
swprintf_s(args, L"%s /c \"%s\"", args, initMintty);
613+
}
614+
else if (streqi(cmderTask.c_str(), L"cmder"))
615+
{
616+
swprintf_s(args, L"%s /k \"%s\"", args, initCmd);
617+
}
561618
}
562619
}
563620

@@ -568,23 +625,42 @@ void StartCmder(std::wstring path = L"", bool is_single_mode = false, std::wstr
568625
SetEnvironmentVariable(L"CMDER_USER_BIN", userBinDirPath);
569626
}
570627

628+
// Try to find m'intty.exe' so ConEmu can launch using %MINTTY_EXE% in external Git for Cmder Mini.
629+
// See: https://github.com/Maximus5/ConEmu/issues/2559 for why this is commented.
630+
631+
/*
632+
if (PathFileExists(vendoredGit))
633+
{
634+
PathCombine(minTTYPath, vendoredGit, L"usr\\bin\\mintty.exe");
635+
SetEnvironmentVariable(L"MINTTY_EXE", minTTYPath);
636+
}
637+
else if (PathFileExists(amdx64Git))
638+
{
639+
PathCombine(minTTYPath, amdx64Git, L"usr\\bin\\mintty.exe");
640+
SetEnvironmentVariable(L"MINTTY_EXE", minTTYPath);
641+
}
642+
else if (PathFileExists(x86Git))
643+
{
644+
PathCombine(minTTYPath, x86Git, L"usr\\bin\\mintty.exe");
645+
SetEnvironmentVariable(L"MINTTY_EXE", minTTYPath);
646+
}
647+
*/
648+
571649
// Ensure EnvironmentVariables are propagated.
572650

573651
STARTUPINFO si = { 0 };
574652

575653
si.cb = sizeof(STARTUPINFO);
576-
#if USE_TASKBAR_API
577-
si.lpTitle = appId;
578-
si.dwFlags = STARTF_TITLEISAPPID;
579-
#endif
654+
#if USE_TASKBAR_API
655+
si.lpTitle = appId;
656+
si.dwFlags = STARTF_TITLEISAPPID;
657+
#endif
580658
PROCESS_INFORMATION pi;
581-
582-
// MessageBox(NULL, terminalPath, _T("Error"), MB_OK);
583-
// MessageBox(NULL, args, _T("Error"), MB_OK);
584659

585660
if (!CreateProcess(terminalPath, args, NULL, NULL, false, 0, NULL, NULL, &si, &pi))
586661
{
587-
if (PathFileExists(windowsTerminalDir)) {
662+
if (PathFileExists(windowsTerminalDir))
663+
{
588664
MessageBox(NULL, _T("Unable to create the Windows Terminal process!"), _T("Error"), MB_OK);
589665
}
590666
else if (PathFileExists(conEmuDir))
@@ -729,15 +805,13 @@ cmderOptions GetOption()
729805
wchar_t conEmuDir[MAX_PATH] = { 0 };
730806
wchar_t vendorDir[MAX_PATH] = { 0 };
731807
wchar_t exeDir[MAX_PATH] = { 0 };
732-
wchar_t cmdInit[MAX_PATH] = { 0 };
733808

734809
GetModuleFileName(NULL, exeDir, sizeof(exeDir));
735810
PathRemoveFileSpec(exeDir);
736811

737812
PathCombine(vendorDir, exeDir, L"vendor");
738813
PathCombine(windowsTerminalDir, vendorDir, L"windows-terminal");
739814
PathCombine(conEmuDir, vendorDir, L"ConEmu-Maximus5");
740-
PathCombine(cmdInit, vendorDir, L"init.bat");
741815

742816
szArgList = CommandLineToArgvW(GetCommandLine(), &argCount);
743817

@@ -868,14 +942,11 @@ cmderOptions GetOption()
868942
cmderOptions.error = true;
869943
}
870944
}
871-
872945
}
873946

874-
if (!PathFileExists(windowsTerminalDir) && !PathFileExists(conEmuDir))
947+
if (!PathFileExists(windowsTerminalDir) && !PathFileExists(conEmuDir) && streqi(cmderOptions.cmderTask.c_str(), L""))
875948
{
876-
cmderOptions.cmderTask = L"/k \"";
877-
cmderOptions.cmderTask += cmdInit;
878-
cmderOptions.cmderTask += L"\"";
949+
cmderOptions.cmderTask = L"cmder";
879950
}
880951

881952
if (cmderOptions.error == true)
@@ -909,13 +980,12 @@ int APIENTRY _tWinMain(_In_ HINSTANCE hInstance,
909980

910981
GetModuleFileName(NULL, exeDir, sizeof(exeDir));
911982
PathRemoveFileSpec(exeDir);
912-
913-
PathCombine(windowsTerminalDir, exeDir, L"vendor\\windows-terminal");
983+
PathCombine(windowsTerminalDir, exeDir, L"vendor\\windows-terminal");
914984

915985
if (cmderOptions.registerApp == true)
916986
{
917-
if (PathFileExists(windowsTerminalDir))
918-
{
987+
if (PathFileExists(windowsTerminalDir))
988+
{
919989
RegisterShellMenu(cmderOptions.cmderRegScope, SHELL_MENU_REGISTRY_PATH_BACKGROUND, cmderOptions.cmderCfgRoot, cmderOptions.cmderSingle);
920990
RegisterShellMenu(cmderOptions.cmderRegScope, SHELL_MENU_REGISTRY_PATH_LISTITEM, cmderOptions.cmderCfgRoot, cmderOptions.cmderSingle);
921991
RegisterShellMenu(cmderOptions.cmderRegScope, SHELL_MENU_REGISTRY_DRIVE_PATH_BACKGROUND, cmderOptions.cmderCfgRoot, cmderOptions.cmderSingle);
@@ -946,4 +1016,4 @@ int APIENTRY _tWinMain(_In_ HINSTANCE hInstance,
9461016
}
9471017

9481018
return 0;
949-
}
1019+
}

0 commit comments

Comments
 (0)