Merge pull request #5537 from RaiKoHoff/Dev_Master

fix: several minor corrections
This commit is contained in:
Pairi Daiza 2026-02-17 19:42:46 +01:00 committed by GitHub
commit 921383dfae
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 98 additions and 5 deletions

View File

@ -114,6 +114,29 @@ Resource-based MUI system with 27+ locales. Each locale has a directory `np3_LAN
Always use `SciCall.h` wrappers (e.g., `SciCall_GetTextLength()`) instead of raw `SendMessage(hwnd, SCI_XXX, ...)`. The wrappers use Scintilla's direct function pointer for performance.
Add missing wrapper calls to `SciCall.h` if needed.
#### SciCall.h wrapper macros
Wrappers are declared using macros. The naming convention is `DeclareSciCall{V|R}{0|01|1|2}`:
- **V** = void return, **R** = has return value
- **0** = no parameters, **1** = one parameter (wParam), **2** = two parameters (wParam + lParam)
- **01** = optional second parameter only (wParam=0, lParam=var) — used when the SCI message takes lParam but not wParam
```c
// Examples:
DeclareSciCallV0(Undo, UNDO); // SciCall_Undo()
DeclareSciCallV1(SetTechnology, SETTECHNOLOGY, int, technology); // SciCall_SetTechnology(int)
DeclareSciCallV2(ScrollVertical, SCROLLVERTICAL, DocLn, docLn, int, subLn); // SciCall_ScrollVertical(DocLn, int)
DeclareSciCallR0(GetTextLength, GETTEXTLENGTH, DocPos); // DocPos SciCall_GetTextLength()
DeclareSciCallR1(SupportsFeature, SUPPORTSFEATURE, bool, int, feature); // bool SciCall_SupportsFeature(int)
```
The `msg` argument is the suffix after `SCI_` (e.g., `UNDO` for `SCI_UNDO`).
### Scintilla / Lexilla versions
The vendored Scintilla (5.5.8) and Lexilla (5.4.6) have Notepad3-specific patches in `scintilla\np3_patches\` and `lexilla\np3_patches\`. Version numbers are in `scintilla\version.txt` and `lexilla\version.txt`. When evaluating new Scintilla APIs, check the offline docs in `scintilla\doc\` and `lexilla\doc\`.
### Adding a new syntax lexer
1. Create `src\StyleLexers\styleLexNEW.c` following existing lexer patterns
@ -124,3 +147,12 @@ Add missing wrapper calls to `SciCall.h` if needed.
### Global state
Application state is centralized in global structs in `Notepad3.c``Globals`, `Settings`, `Settings2`, `Flags`, `Paths`. Prefer accessing these through their defined interfaces rather than adding new globals.
### INI file / portable-app design
Notepad3 follows a **portable-app** design for its configuration file (`Notepad3.ini`):
- **No auto-creation on first run**: If no INI file is found, the application runs with defaults. The path is stored in `Paths.IniFileDefault` (not `Paths.IniFile`) so the user can explicitly create it via "Save Settings Now".
- **Admin redirect**: An administrator can place `Notepad3.ini=<path>` in `[Notepad3]` section of the app-directory INI to redirect to a per-user path. Up to 2 levels of redirect are supported. Redirect targets **are** auto-created (the admin intended them to exist).
- **Key paths**: `Paths.IniFile` = active writable INI (empty if none exists), `Paths.IniFileDefault` = fallback path for "Save Settings Now" recovery.
- **Configuration code**: All INI init logic lives in `src\Config\Config.cpp``FindIniFile()``TestIniFile()``CreateIniFile()``LoadSettings()`.

View File

@ -1000,10 +1000,23 @@ static bool _HandleIniFileRedirect(LPCWSTR lpszSecName, LPCWSTR lpszKeyName, HPA
Path_Sanitize(hredirect);
Path_FreeExtra(hredirect, 0);
if (_CheckAndSetIniFile(hredirect)) {
// Redirect target exists — use it
Path_Swap(hpth_in_out, hredirect);
}
else {
Path_CanonicalizeEx(hpth_in_out, Paths.ModuleDirectory);
// Redirect target doesn't exist — try to create it
// (admin explicitly configured this redirect)
Path_ExpandEnvStrings(hredirect);
if (Path_IsRelative(hredirect)) {
Path_RelativeToApp(hredirect, false, false, true);
}
if (CreateIniFile(hredirect, NULL)) {
Path_Swap(hpth_in_out, hredirect);
} else {
// Creation failed — remember target for "Save Settings Now"
Path_Reset(Paths.IniFileDefault, Path_Get(hredirect));
Path_CanonicalizeEx(hpth_in_out, Paths.ModuleDirectory);
}
}
result = true;
}
@ -1093,7 +1106,12 @@ extern "C" bool CreateIniFile(const HPATHL hini_pth, DWORD* pdwFileSize_out)
Path_RemoveFileSpec(hdir_path);
if (Path_IsNotEmpty(hdir_path)) {
// Use SHCreateDirectoryExW to create all intermediate directories - fixes #5075
SHCreateDirectoryExW(NULL, Path_Get(hdir_path), NULL);
HRESULT const hr = SHCreateDirectoryExW(NULL, Path_Get(hdir_path), NULL);
if (FAILED(hr) && (hr != HRESULT_FROM_WIN32(ERROR_ALREADY_EXISTS))) {
Path_Release(hdir_path);
if (pdwFileSize_out) { *pdwFileSize_out = 0UL; }
return false;
}
}
Path_Release(hdir_path);
@ -1113,6 +1131,8 @@ extern "C" bool CreateIniFile(const HPATHL hini_pth, DWORD* pdwFileSize_out)
StrgFormat(msg, L"CreateIniFile(%s): FAILED TO CREATE INITIAL INI FILE!", fileName);
MsgBoxLastError(StrgGet(msg), 0);
StrgDestroy(msg);
if (pdwFileSize_out) { *pdwFileSize_out = 0UL; }
return false;
}
} else {
HANDLE hFile = CreateFileW(Path_Get(hini_pth),
@ -1137,7 +1157,7 @@ extern "C" bool CreateIniFile(const HPATHL hini_pth, DWORD* pdwFileSize_out)
*pdwFileSize_out = dwFileSize;
}
return CanAccessPath(Paths.IniFile, GENERIC_WRITE);
return CanAccessPath(hini_pth, GENERIC_WRITE);
}
return false;
}

View File

@ -8300,13 +8300,21 @@ static void _UpdateIndicators(const int indicator, const int indicator2nd,
break; // wrong match
}
// URL-specific: if match ends with single-quote and is preceded by one, strip trailing quote
DocPos mlen_adj = mlen;
if ((indicator == INDIC_NP3_HYPERLINK) && (mlen_adj > 4)) {
if ((SciCall_GetCharAt(end - 1) == '\'') && (start > 0) && (SciCall_GetCharAt(start - 1) == '\'')) {
--mlen_adj;
}
}
_ClearIndicatorInRange(indicator, indicator2nd, start_m, end);
SciCall_SetIndicatorCurrent(indicator);
SciCall_IndicatorFillRange(start, mlen);
SciCall_IndicatorFillRange(start, mlen_adj);
if (indicator2nd >= 0) {
SciCall_SetIndicatorCurrent(indicator2nd);
SciCall_IndicatorFillRange(start, mlen);
SciCall_IndicatorFillRange(start, mlen_adj);
}
// next occurrence

View File

@ -18,6 +18,7 @@
#include <shlobj.h>
#include <shellapi.h>
#include <propkey.h>
#include <ctype.h>
#include <wchar.h>
@ -295,6 +296,36 @@ HRESULT PrivateSetCurrentProcessExplicitAppUserModelID(PCWSTR AppID)
}
//=============================================================================
//
// SetWindowAppUserModelID()
//
HRESULT SetWindowAppUserModelID(HWND hwnd, PCWSTR AppID)
{
if (!hwnd || StrIsEmpty(AppID)) {
return S_OK;
}
if (StringCchCompareXI(AppID, L"(default)") == 0) {
return S_OK;
}
IPropertyStore* pps = NULL;
HRESULT hr = SHGetPropertyStoreForWindow(hwnd, &IID_IPropertyStore, (void**)&pps);
if (SUCCEEDED(hr)) {
PROPVARIANT pv;
PropVariantInit(&pv);
pv.vt = VT_LPWSTR;
hr = SHStrDupW(AppID, &pv.pwszVal);
if (SUCCEEDED(hr)) {
hr = pps->lpVtbl->SetValue(pps, &PKEY_AppUserModel_ID, &pv);
PropVariantClear(&pv);
}
pps->lpVtbl->Release(pps);
}
return hr;
}
//=============================================================================
//
// IsProcessElevated()

View File

@ -417,6 +417,7 @@ static inline int IsFullHD(HWND hwnd, int resX, int resY)
// ----------------------------------------------------------------------------
HRESULT PrivateSetCurrentProcessExplicitAppUserModelID(PCWSTR AppID);
HRESULT SetWindowAppUserModelID(HWND hwnd, PCWSTR AppID);
bool IsProcessElevated();
//bool IsUserAdmin();

View File

@ -1773,6 +1773,7 @@ HWND InitInstance(const HINSTANCE hInstance, int nCmdShow)
DrawMenuBar(hwndMain);
Globals.hwndMain = hwndMain; // make main window globaly available
SetWindowAppUserModelID(hwndMain, Settings2.AppUserModelID);
HPATHL hfile_pth = Path_Copy(s_pthArgFilePath);
FileLoadFlags fLoadFlags = FLF_None;