mirror of
https://github.com/rizonesoft/Notepad3.git
synced 2026-06-14 21:09:05 +08:00
Merge pull request #5537 from RaiKoHoff/Dev_Master
fix: several minor corrections
This commit is contained in:
commit
921383dfae
32
.github/copilot-instructions.md
vendored
32
.github/copilot-instructions.md
vendored
@ -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()`.
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
12
src/Edit.c
12
src/Edit.c
@ -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
|
||||
|
||||
@ -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()
|
||||
|
||||
@ -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();
|
||||
|
||||
@ -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;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user