From bb0038cc756ea9e0221abc7370ed317877eaed94 Mon Sep 17 00:00:00 2001 From: Rainer Kottenhoff Date: Fri, 6 Mar 2026 18:11:52 +0100 Subject: [PATCH] fix: handling if file's parent dir is deleted. --- .github/copilot-instructions.md | 24 ++++++++++++++ CLAUDE.md | 50 +++++++++++++++++++++++++++++ language/common_res.h | 1 + language/np3_af_za/strings_af_za.rc | 1 + language/np3_be_by/strings_be_by.rc | 1 + language/np3_de_de/strings_de_de.rc | 2 +- language/np3_el_gr/strings_el_gr.rc | 1 + language/np3_en_gb/strings_en_gb.rc | 1 + language/np3_en_us/strings_en_us.rc | 1 + language/np3_es_es/strings_es_es.rc | 1 + language/np3_fi_fi/strings_fi_fi.rc | 1 + language/np3_fr_fr/strings_fr_fr.rc | 1 + language/np3_hi_in/strings_hi_in.rc | 1 + language/np3_hu_hu/strings_hu_hu.rc | 1 + language/np3_id_id/strings_id_id.rc | 1 + language/np3_it_it/strings_it_it.rc | 1 + language/np3_ja_jp/strings_ja_jp.rc | 1 + language/np3_ko_kr/strings_ko_kr.rc | 1 + language/np3_nl_nl/strings_nl_nl.rc | 1 + language/np3_pl_pl/strings_pl_pl.rc | 1 + language/np3_pt_br/strings_pt_br.rc | 1 + language/np3_pt_pt/strings_pt_pt.rc | 1 + language/np3_ru_ru/strings_ru_ru.rc | 1 + language/np3_sk_sk/strings_sk_sk.rc | 1 + language/np3_sv_se/strings_sv_se.rc | 1 + language/np3_tr_tr/strings_tr_tr.rc | 1 + language/np3_vi_vn/strings_vi_vn.rc | 1 + language/np3_zh_cn/strings_zh_cn.rc | 1 + language/np3_zh_tw/strings_zh_tw.rc | 1 + src/Notepad3.c | 44 +++++++++++++++++++++++++ todo/TODO.md | 9 ++++-- 31 files changed, 151 insertions(+), 4 deletions(-) diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index 74ee8412f..d087471c3 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -97,6 +97,26 @@ EDITLEXER lexXXX = { Resource-based MUI system with 27+ locales. Each locale has a directory `np3_LANG_COUNTRY\` containing resource `.rc` files. Language DLLs are built as separate projects in the solution. +### Adding String Resources + +1. Add `#define IDS_MUI_XXX ` to `language\common_res.h` (use next available ID in the appropriate range: 13xxx for errors/warnings, 14xxx for info/prompts) +2. Add the English string to `language\np3_en_us\strings_en_us.rc` in the matching `STRINGTABLE` block +3. Add the same English text as placeholder to all other 25 locale `strings_*.rc` files (translators update later) +4. Use `InfoBoxLng()` / `MessageBoxLng()` with `MB_YESNO`, `MB_ICONWARNING`, etc. to display; check result with `IsYesOkay()` +5. `Settings.MuteMessageBeep` controls whether to use `InfoBoxLng` (silent) or `MessageBoxLng` (with sound) — always provide both paths + +### File I/O Flow + +- **`FileSave()`** (`src\Notepad3.c`) — Main save dispatcher. Handles Save, Save As, Save Copy. + Calls `FileIO()` → `EditSaveFile()` (`src\Edit.c`) +- **`FileLoad()`** (`src\Notepad3.c`) — Main load dispatcher. + Calls `FileIO()` → `EditLoadFile()` (`src\Edit.c`) +- **`EditSaveFile()`** supports atomic save (temp file + `ReplaceFileW`) controlled by `Settings2.AtomicFileSave` +- **Error handling**: `Globals.dwLastError` holds the Win32 error code after failed I/O. + `FileSave()` checks specific codes (`ERROR_ACCESS_DENIED`, `ERROR_PATH_NOT_FOUND`) before falling back to generic error. +- **File watching**: `InstallFileWatching()` uses `FindFirstChangeNotificationW` on the parent directory. + Must be stopped before save (`InstallFileWatching(false)`) and restarted after (`InstallFileWatching(true)`). + ### PCRE2 Regex Engine (`scintilla\pcre2\`) PCRE2 10.47 replaced the archived Oniguruma library. The Scintilla integration lives in `scintilla\pcre2\scintilla\PCRE2RegExEngine.cxx`, compiled with `SCI_OWNREGEX` to override Scintilla's built-in regex. @@ -184,6 +204,10 @@ Notepad3 follows a **portable-app** design for its configuration file (`Notepad3 - **MiniPath** follows the same portable INI and admin-redirect pattern (`minipath\src\Config.cpp`). Redirect targets are auto-created via `CreateIniFileEx()`. - **New parameters**: When adding new `Settings2` (or other INI) parameters, always document them as commented entries in `Build\Notepad3.ini` +### Creating Directories + +Use `SHCreateDirectoryExW(NULL, path, NULL)` to recursively create directory trees (requires ``, already included in core modules). Check result: `SUCCEEDED(hr) || (hr == HRESULT_FROM_WIN32(ERROR_ALREADY_EXISTS))`. See `CreateIniFile()` in `src\Config\Config.cpp` for the reference pattern. + ### Undo/Redo transactions Use `_BEGIN_UNDO_ACTION_` / `_END_UNDO_ACTION_` macros (defined in `Notepad3.h`) to group Scintilla operations into single undo steps. These also handle notification limiting during bulk edits. diff --git a/CLAUDE.md b/CLAUDE.md index 9b527e0ef..825ce5277 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -109,6 +109,14 @@ To add a new lexer: create `styleLexNEW.c`, define the `EDITLEXER` struct, regis Resource-based MUI system with 27+ locales. Each locale has a `np3_LANG_COUNTRY\` directory with `.rc` files. Language packs are built as separate DLLs (separate projects in the solution). +### Adding String Resources + +1. Add `#define IDS_MUI_XXX ` to `language\common_res.h` (use next available ID in the appropriate range: 13xxx for errors/warnings, 14xxx for info/prompts) +2. Add the English string to `language\np3_en_us\strings_en_us.rc` in the matching `STRINGTABLE` block +3. Add the same English text as placeholder to all other 25 locale `strings_*.rc` files (translators update later) +4. Use `InfoBoxLng()` / `MessageBoxLng()` with `MB_YESNO`, `MB_ICONWARNING`, etc. to display; check result with `IsYesOkay()` +5. `Settings.MuteMessageBeep` controls whether to use `InfoBoxLng` (silent) or `MessageBoxLng` (with sound) — always provide both paths + ### Configuration / Portable Design - INI file alongside executable (`Notepad3.ini`), no registry usage @@ -119,6 +127,22 @@ Resource-based MUI system with 27+ locales. Each locale has a `np3_LANG_COUNTRY\ - **MiniPath** follows the same portable INI and admin-redirect pattern (`minipath\src\Config.cpp`). Redirect targets are auto-created via `CreateIniFileEx()`. - **New parameters**: When adding new `Settings2` (or other INI) parameters, always document them as commented entries in `Build\Notepad3.ini` +### Creating Directories + +Use `SHCreateDirectoryExW(NULL, path, NULL)` to recursively create directory trees (requires ``, already included in core modules). Check result: `SUCCEEDED(hr) || (hr == HRESULT_FROM_WIN32(ERROR_ALREADY_EXISTS))`. See `CreateIniFile()` in `src\Config\Config.cpp` for the reference pattern. + +### File I/O Flow + +- **`FileSave()`** (`src\Notepad3.c`) — Main save dispatcher. Handles Save, Save As, Save Copy. + Calls `FileIO()` → `EditSaveFile()` (`src\Edit.c`) +- **`FileLoad()`** (`src\Notepad3.c`) — Main load dispatcher. + Calls `FileIO()` → `EditLoadFile()` (`src\Edit.c`) +- **`EditSaveFile()`** supports atomic save (temp file + `ReplaceFileW`) controlled by `Settings2.AtomicFileSave` +- **Error handling**: `Globals.dwLastError` holds the Win32 error code after failed I/O. + `FileSave()` checks specific codes (`ERROR_ACCESS_DENIED`, `ERROR_PATH_NOT_FOUND`) before falling back to generic error. +- **File watching**: `InstallFileWatching()` uses `FindFirstChangeNotificationW` on the parent directory. + Must be stopped before save (`InstallFileWatching(false)`) and restarted after (`InstallFileWatching(true)`). + ### PCRE2 Regex Engine (`scintilla\pcre2\`) PCRE2 10.47 replaced the archived Oniguruma library. The Scintilla integration lives in `scintilla\pcre2\scintilla\PCRE2RegExEngine.cxx`, compiled with `SCI_OWNREGEX` to override Scintilla's built-in regex. @@ -179,3 +203,29 @@ Application state is centralized in global structs (`Globals`, `Settings`, `Sett ### Undo/Redo Transactions Use `_BEGIN_UNDO_ACTION_` / `_END_UNDO_ACTION_` macros (defined in `Notepad3.h`) to group Scintilla operations into single undo steps. These also handle notification limiting during bulk edits. + +## Python Environment + +A Python 3.14 virtual environment is available at `.venv\` for scripting tasks (batch file manipulation, locale file updates, code generation, etc.). + +```bash +# Run a script (from project root, in bash/Cygwin) +.venv/Scripts/python.exe + +# Install packages +.venv/Scripts/pip.exe install +``` + +Use this venv instead of system Python (which may not be installed). Useful for bulk operations across the 26 locale `strings_*.rc` files. + +## Key File Paths (Quick Reference) + +| Pattern | Purpose | +|---------|---------| +| `language/common_res.h` | String resource ID definitions | +| `language/np3_*/strings_*.rc` | Locale string tables (26 files) | +| `Build/Notepad3.ini` | Reference INI with documented settings | +| `src/Notepad3.c:FileSave()` | Save flow entry point | +| `src/Edit.c:EditSaveFile()` | Actual file write logic | +| `src/Config/Config.cpp` | INI management, settings load/save | +| `src/Dialogs.c:SaveFileDlg()` | Save As dialog | diff --git a/language/common_res.h b/language/common_res.h index 91d1a8dd6..b351454be 100644 --- a/language/common_res.h +++ b/language/common_res.h @@ -170,6 +170,7 @@ #define IDS_MUI_INF_PRSVFILEMODTM 13024 #define IDS_MUI_WARN_STYLE_RESET 13025 #define IDS_MUI_ASK_INSTANCE_EXISTS 13026 +#define IDS_MUI_ERR_PATHNOTFOUND 13027 #define IDS_MUI_SELRECT 14000 #define IDS_MUI_BUFFERTOOSMALL 14001 diff --git a/language/np3_af_za/strings_af_za.rc b/language/np3_af_za/strings_af_za.rc index a4c7b75dd..09d289e1b 100644 --- a/language/np3_af_za/strings_af_za.rc +++ b/language/np3_af_za/strings_af_za.rc @@ -129,6 +129,7 @@ STRINGTABLE BEGIN IDS_MUI_ERR_LOADFILE "Kon nie ""%s"" laai nie" IDS_MUI_ERR_SAVEFILE "Kon nie ""%s"" stoor nie" + IDS_MUI_ERR_PATHNOTFOUND "The path for ""%s"" no longer exists.\nRecreate the path and save the file?" IDS_MUI_ERR_DLG_FORMAT "Fout '%s', oorsaak:\n%s(ID:%d)\n" IDS_MUI_ERR_BROWSE "Geen lêerblaaier plugin is gevind nie\nDie MiniPath-lêerblaaier plugin kan afgelaai word vanaf https://rizonesoft.com" IDS_MUI_ERR_GREPWIN "Geen lêer soek-inprop is gevind nie\nDie grepWinNP3 lêersoek plugin kan afgelaai word vanaf https://rizonesoft.com" diff --git a/language/np3_be_by/strings_be_by.rc b/language/np3_be_by/strings_be_by.rc index e442545db..8acb6eed6 100644 --- a/language/np3_be_by/strings_be_by.rc +++ b/language/np3_be_by/strings_be_by.rc @@ -129,6 +129,7 @@ STRINGTABLE BEGIN IDS_MUI_ERR_LOADFILE "Памылка чытання «%s»" IDS_MUI_ERR_SAVEFILE "Памылка захоўвання «%s»" + IDS_MUI_ERR_PATHNOTFOUND "The path for ""%s"" no longer exists.\nRecreate the path and save the file?" IDS_MUI_ERR_DLG_FORMAT "Памылка '%s', прычына:\n%s(ID:%d)\n" IDS_MUI_ERR_BROWSE "Не знойдзены плагін аглядніка файлаў\nПлагін MiniPath можна спампаваць з сайта https://rizonesoft.com" IDS_MUI_ERR_GREPWIN "Не знойдзены плагін для пошука ў файлах\nПлагін grepWinNP3 можна спампаваць з сайта https://rizonesoft.com" diff --git a/language/np3_de_de/strings_de_de.rc b/language/np3_de_de/strings_de_de.rc index e805a6c45..16ec6af75 100644 --- a/language/np3_de_de/strings_de_de.rc +++ b/language/np3_de_de/strings_de_de.rc @@ -129,7 +129,7 @@ STRINGTABLE BEGIN IDS_MUI_ERR_LOADFILE "Fehler beim laden ""%s""" IDS_MUI_ERR_SAVEFILE "Fehler beim speichern ""%s""" - IDS_MUI_ERR_DLG_FORMAT "Fehler '%s', weil:\n%s(ID:%d)\n" + IDS_MUI_ERR_PATHNOTFOUND "Der Dateipfad zu ""%s"" existiert nicht länger.\nErzeuge den Dateipfad neu und speichere die Datei?" IDS_MUI_ERR_BROWSE "Kein Datei-Browser-Plugin gefunden\nDas MiniPath Datei-Browser-Plugin kann hier https://rizonesoft.com herunter geladen werden" IDS_MUI_ERR_GREPWIN "Kein Datei-Suchen-Plugin gefunden\nDas grepWinNP3 Datei-Suchen-Plugin kann hier https://rizonesoft.com herunter geladen werden" IDS_MUI_ERR_MRUDLG "Es kann nicht auf die ausgewählte Datei zugegriffen werden!\nMöchtest Du den Eintrag aus der Liste entfernen?" diff --git a/language/np3_el_gr/strings_el_gr.rc b/language/np3_el_gr/strings_el_gr.rc index 1a7992c60..e71e72a23 100644 --- a/language/np3_el_gr/strings_el_gr.rc +++ b/language/np3_el_gr/strings_el_gr.rc @@ -129,6 +129,7 @@ STRINGTABLE BEGIN IDS_MUI_ERR_LOADFILE "Σφάλμα φόρτωσης του ""%s""" IDS_MUI_ERR_SAVEFILE "Σφάλμα αποθήκευσης του ""%s""" + IDS_MUI_ERR_PATHNOTFOUND "The path for ""%s"" no longer exists.\nRecreate the path and save the file?" IDS_MUI_ERR_DLG_FORMAT "Σφάλμα '%s'. Αιτία:\n%s(ID:%d)\n" IDS_MUI_ERR_BROWSE "Δεν βρέθηκε το πρόσθετο περιήγησης αρχείων\nΜπορείτε να κάνετε λήψη του πρόσθετου περιήγησης αρχείων MiniPath από https://rizonesoft.com" IDS_MUI_ERR_GREPWIN "Δεν βρέθηκε το πρόσθετο αναζήτησης αρχείων\nΜπορείτε να κάνετε λήψη του πρόσθετου αναζήτησης αρχείων grepWinNP3 από https://rizonesoft.com" diff --git a/language/np3_en_gb/strings_en_gb.rc b/language/np3_en_gb/strings_en_gb.rc index 74b43b660..c8f1c396b 100644 --- a/language/np3_en_gb/strings_en_gb.rc +++ b/language/np3_en_gb/strings_en_gb.rc @@ -129,6 +129,7 @@ STRINGTABLE BEGIN IDS_MUI_ERR_LOADFILE "Error loading ""%s""" IDS_MUI_ERR_SAVEFILE "Error saving ""%s""" + IDS_MUI_ERR_PATHNOTFOUND "The path for ""%s"" no longer exists.\nRecreate the path and save the file?" IDS_MUI_ERR_DLG_FORMAT "Error '%s', cause:\n%s(ID:%d)\n" IDS_MUI_ERR_BROWSE "No file browser plugin was found\nThe MiniPath file browser plugin can be downloaded from https://rizonesoft.com" IDS_MUI_ERR_GREPWIN "No file search plugin was found\nThe grepWinNP3 file search plugin can be downloaded from https://rizonesoft.com" diff --git a/language/np3_en_us/strings_en_us.rc b/language/np3_en_us/strings_en_us.rc index acdca6681..7aeb7351d 100644 --- a/language/np3_en_us/strings_en_us.rc +++ b/language/np3_en_us/strings_en_us.rc @@ -129,6 +129,7 @@ STRINGTABLE BEGIN IDS_MUI_ERR_LOADFILE "Error loading ""%s""" IDS_MUI_ERR_SAVEFILE "Error saving ""%s""" + IDS_MUI_ERR_PATHNOTFOUND "The path for ""%s"" no longer exists.\nRecreate the path and save the file?" IDS_MUI_ERR_DLG_FORMAT "Error '%s', cause:\n%s(ID:%d)\n" IDS_MUI_ERR_BROWSE "No file browser plugin was found\nThe MiniPath file browser plugin can be downloaded from https://rizonesoft.com" IDS_MUI_ERR_GREPWIN "No file search plugin was found\nThe grepWinNP3 file search plugin can be downloaded from https://rizonesoft.com" diff --git a/language/np3_es_es/strings_es_es.rc b/language/np3_es_es/strings_es_es.rc index cd73a2350..cb84b78d5 100644 --- a/language/np3_es_es/strings_es_es.rc +++ b/language/np3_es_es/strings_es_es.rc @@ -129,6 +129,7 @@ STRINGTABLE BEGIN IDS_MUI_ERR_LOADFILE "Error cargando ""%s""" IDS_MUI_ERR_SAVEFILE "Error guardando ""%s""" + IDS_MUI_ERR_PATHNOTFOUND "The path for ""%s"" no longer exists.\nRecreate the path and save the file?" IDS_MUI_ERR_DLG_FORMAT "Error '%s', causa:\n%s(ID:%d)\n" IDS_MUI_ERR_BROWSE "No se encontró plug-in para el navegador de archivos\nEl plug-in de navegador de archivos MiniPath se puede descargar desde https://rizonesoft.com" IDS_MUI_ERR_GREPWIN "No se encontró plug-in de búsqueda de archivos\nEl plug-in grepWinNP3 de búsqueda de archivos se puede descargar desde https://rizonesoft.com" diff --git a/language/np3_fi_fi/strings_fi_fi.rc b/language/np3_fi_fi/strings_fi_fi.rc index af4262f39..ad9ea6342 100644 --- a/language/np3_fi_fi/strings_fi_fi.rc +++ b/language/np3_fi_fi/strings_fi_fi.rc @@ -129,6 +129,7 @@ STRINGTABLE BEGIN IDS_MUI_ERR_LOADFILE "Virhe ladattaessa ""%s""" IDS_MUI_ERR_SAVEFILE "Virhe tallennettaessa ""%s""" + IDS_MUI_ERR_PATHNOTFOUND "The path for ""%s"" no longer exists.\nRecreate the path and save the file?" IDS_MUI_ERR_DLG_FORMAT "Virhe '%s', syy:\n%s(ID:%d)\n" IDS_MUI_ERR_BROWSE "Tiedostoselaimen laajennusta ei löytynyt\nMiniPath-tiedostoselaimen laajennuksen voi ladata osoitteesta https://rizonesoft.com" IDS_MUI_ERR_GREPWIN "Tiedostonhakulaajennusta ei löytynyt\nGrepWinNP3-tiedostonhakulaajennuksen voi ladata osoitteesta https://rizonesoft.com" diff --git a/language/np3_fr_fr/strings_fr_fr.rc b/language/np3_fr_fr/strings_fr_fr.rc index 9279869e2..61a214e23 100644 --- a/language/np3_fr_fr/strings_fr_fr.rc +++ b/language/np3_fr_fr/strings_fr_fr.rc @@ -129,6 +129,7 @@ STRINGTABLE BEGIN IDS_MUI_ERR_LOADFILE "Erreur de chargement de ""%s""" IDS_MUI_ERR_SAVEFILE "Erreur de sauvegarde de ""%s""" + IDS_MUI_ERR_PATHNOTFOUND "The path for ""%s"" no longer exists.\nRecreate the path and save the file?" IDS_MUI_ERR_DLG_FORMAT "Erreur '%s', cause :\n%s(ID:%d)\n" IDS_MUI_ERR_BROWSE "Aucun plugin de navigateur de fichiers n'a été trouvé\nLe plugin du navigateur de fichiers MiniPath peut être téléchargé à partir de https://rizonesoft.com" IDS_MUI_ERR_GREPWIN "Aucun plugin de recherche de fichiers n'a été trouvé\nLe plugin de recherche de fichiers grepWinNP3 peut être téléchargé depuis https://rizonesoft.com" diff --git a/language/np3_hi_in/strings_hi_in.rc b/language/np3_hi_in/strings_hi_in.rc index e9a1fd2d1..9fcbe444c 100644 --- a/language/np3_hi_in/strings_hi_in.rc +++ b/language/np3_hi_in/strings_hi_in.rc @@ -129,6 +129,7 @@ STRINGTABLE BEGIN IDS_MUI_ERR_LOADFILE """%s"" शुरू करने में त्रुटि" IDS_MUI_ERR_SAVEFILE """%s"" सहेजने में त्रुटि" + IDS_MUI_ERR_PATHNOTFOUND "The path for ""%s"" no longer exists.\nRecreate the path and save the file?" IDS_MUI_ERR_DLG_FORMAT "त्रुटि '%s', कारण:\n%s(ID:%d)\n" IDS_MUI_ERR_BROWSE "कोई फ़ाईल ब्राउज़र plugin नहीं मिला।\nकृपया MiniPath फ़ाईल ब्राउज़र plugin यहाँ से डाउनलोड करें: https://rizonesoft.com" IDS_MUI_ERR_GREPWIN "कोई फ़ाईल सर्च plugin नहीं मिला।\ngrepWinNP3 सर्च plugin कृपया यहाँ से डाउनलोड करें: https://rizonesoft.com" diff --git a/language/np3_hu_hu/strings_hu_hu.rc b/language/np3_hu_hu/strings_hu_hu.rc index 5bd20292b..10a99c96b 100644 --- a/language/np3_hu_hu/strings_hu_hu.rc +++ b/language/np3_hu_hu/strings_hu_hu.rc @@ -129,6 +129,7 @@ STRINGTABLE BEGIN IDS_MUI_ERR_LOADFILE "Hiba ""%s"" betöltésekor" IDS_MUI_ERR_SAVEFILE "Hiba ""%s"" mentésekor" + IDS_MUI_ERR_PATHNOTFOUND "The path for ""%s"" no longer exists.\nRecreate the path and save the file?" IDS_MUI_ERR_DLG_FORMAT "Hiba '%s', oka:\n%s(ID:%d)\n" IDS_MUI_ERR_BROWSE "Fájlböngésző plugin nem található\nA MiniPath fájlböngésző plugin letölthető a https://rizonesoft.com címről" IDS_MUI_ERR_GREPWIN "Fájlkereső plugin nem található\nA grepWinNP3 fájlkereső plugin letölthető a https://rizonesoft.com címről" diff --git a/language/np3_id_id/strings_id_id.rc b/language/np3_id_id/strings_id_id.rc index afbc7a857..a55d9a177 100644 --- a/language/np3_id_id/strings_id_id.rc +++ b/language/np3_id_id/strings_id_id.rc @@ -129,6 +129,7 @@ STRINGTABLE BEGIN IDS_MUI_ERR_LOADFILE "Kesalahan memuat ""%s""" IDS_MUI_ERR_SAVEFILE "Kesalahan menyimpan ""%s""" + IDS_MUI_ERR_PATHNOTFOUND "The path for ""%s"" no longer exists.\nRecreate the path and save the file?" IDS_MUI_ERR_DLG_FORMAT "Kesalahan pada '%s', penyebab:\n%s(ID:%d)\n" IDS_MUI_ERR_BROWSE "Tidak ditemukan plugin penelusuran berkas\nPlugin penelusuran berkas MiniPath dapat diunduh di https://rizonesoft.com" IDS_MUI_ERR_GREPWIN "Tidak ditemukan plugin pencarian berkas\nPlugin pencarian berkas grepWinNP3 dapat diunduh di https://rizonesoft.com" diff --git a/language/np3_it_it/strings_it_it.rc b/language/np3_it_it/strings_it_it.rc index 885665928..617118717 100644 --- a/language/np3_it_it/strings_it_it.rc +++ b/language/np3_it_it/strings_it_it.rc @@ -129,6 +129,7 @@ STRINGTABLE BEGIN IDS_MUI_ERR_LOADFILE "Errore nell'apertura di ""%s""" IDS_MUI_ERR_SAVEFILE "Errore nel salvataggio di ""%s""" + IDS_MUI_ERR_PATHNOTFOUND "The path for ""%s"" no longer exists.\nRecreate the path and save the file?" IDS_MUI_ERR_DLG_FORMAT "Errore '%s', causa:\n%s(ID:%d)\n" IDS_MUI_ERR_BROWSE "Nessun plugin file browser trovato\nMiniPath può essere scaricato da https://rizonesoft.com" IDS_MUI_ERR_GREPWIN "Nessun plugin ricerca file trovato\nIl plugin ricerca file grepWinNP3 può esssere scaricato da https://rizonesoft.com" diff --git a/language/np3_ja_jp/strings_ja_jp.rc b/language/np3_ja_jp/strings_ja_jp.rc index cedf727c2..53db8f404 100644 --- a/language/np3_ja_jp/strings_ja_jp.rc +++ b/language/np3_ja_jp/strings_ja_jp.rc @@ -129,6 +129,7 @@ STRINGTABLE BEGIN IDS_MUI_ERR_LOADFILE "読込失敗 ""%s""" IDS_MUI_ERR_SAVEFILE "保存失敗 ""%s""" + IDS_MUI_ERR_PATHNOTFOUND "The path for ""%s"" no longer exists.\nRecreate the path and save the file?" IDS_MUI_ERR_DLG_FORMAT "エラー '%s', 原因:\n%s(ID:%d)\n" IDS_MUI_ERR_BROWSE "ファイラーのプラグインがありません\nこのプラグイン MiniPath は以下からダウンロードできます https://rizonesoft.com" IDS_MUI_ERR_GREPWIN "ファイル検索プラグインが見つかりません\nファイル検索プラグインの grepWinNP3 は以下からダウンロードできます https://rizonesoft.com" diff --git a/language/np3_ko_kr/strings_ko_kr.rc b/language/np3_ko_kr/strings_ko_kr.rc index f0d20fc3d..7847c2556 100644 --- a/language/np3_ko_kr/strings_ko_kr.rc +++ b/language/np3_ko_kr/strings_ko_kr.rc @@ -129,6 +129,7 @@ STRINGTABLE BEGIN IDS_MUI_ERR_LOADFILE """%s"" 파일을 불러오는 동안 오류가 발생하였습니다" IDS_MUI_ERR_SAVEFILE """%s"" 파일을 저장하는 동안 오류가 발생하였습니다" + IDS_MUI_ERR_PATHNOTFOUND "The path for ""%s"" no longer exists.\nRecreate the path and save the file?" IDS_MUI_ERR_DLG_FORMAT "오류 '%s', 원인:\n%s(ID:%d)\n" IDS_MUI_ERR_BROWSE "파일 탐색기 플러그인을 찾을 수 없습니다\nMiniPath 파일 탐색기 플러그인은 https://rizonesoft.com에서 다운로드할 수 있습니다" IDS_MUI_ERR_GREPWIN "파일 검색 플러그인을 찾을 수 없습니다\ngrepWinNP3 파일 검색 플러그인은 https://rizonesoft.com에서 다운로드할 수 있습니다" diff --git a/language/np3_nl_nl/strings_nl_nl.rc b/language/np3_nl_nl/strings_nl_nl.rc index cb2fb9fb1..d4411c956 100644 --- a/language/np3_nl_nl/strings_nl_nl.rc +++ b/language/np3_nl_nl/strings_nl_nl.rc @@ -129,6 +129,7 @@ STRINGTABLE BEGIN IDS_MUI_ERR_LOADFILE "Fout bij laden ""%s""" IDS_MUI_ERR_SAVEFILE "Fout bij opslaan ""%s""" + IDS_MUI_ERR_PATHNOTFOUND "The path for ""%s"" no longer exists.\nRecreate the path and save the file?" IDS_MUI_ERR_DLG_FORMAT "Fout '%s', oorzaak:\n%s(ID:%d)\n" IDS_MUI_ERR_BROWSE "Geen bestandsbrowser-plugin gevonden\nDe plugin voor de MiniPath bestandsbrowser kan worden gedownload van https://rizonesoft.com" IDS_MUI_ERR_GREPWIN "Geen plugin voor het doorzoeken van bestanden gevonden\nDe plug-in grepWinNP3 voor het doorzoeken van bestanden kan worden gedownload van https://rizonesoft.com" diff --git a/language/np3_pl_pl/strings_pl_pl.rc b/language/np3_pl_pl/strings_pl_pl.rc index c0ce643c9..abf5e0c09 100644 --- a/language/np3_pl_pl/strings_pl_pl.rc +++ b/language/np3_pl_pl/strings_pl_pl.rc @@ -129,6 +129,7 @@ STRINGTABLE BEGIN IDS_MUI_ERR_LOADFILE "Błąd podczas ładowania ""%s""" IDS_MUI_ERR_SAVEFILE "Błąd podczas zapisu ""%s""" + IDS_MUI_ERR_PATHNOTFOUND "The path for ""%s"" no longer exists.\nRecreate the path and save the file?" IDS_MUI_ERR_DLG_FORMAT "Błąd '%s', powód:\n%s(ID:%d)\n" IDS_MUI_ERR_BROWSE "Nie znaleziono wtyczki przeglądarki pliku\nWtyczkę przeglądarki pliku do MiniPath można pobrać z https://rizonesoft.com" IDS_MUI_ERR_GREPWIN "Nie znaleziono wtyczki wyszukiwania pliku.\Wtyczkę wyszukiwania pliku programu grepWinNP3 można pobrać ze strony https://rizonesoft.com" diff --git a/language/np3_pt_br/strings_pt_br.rc b/language/np3_pt_br/strings_pt_br.rc index 6e23c4980..36e40a45e 100644 --- a/language/np3_pt_br/strings_pt_br.rc +++ b/language/np3_pt_br/strings_pt_br.rc @@ -129,6 +129,7 @@ STRINGTABLE BEGIN IDS_MUI_ERR_LOADFILE "Erro carregando ""%s""" IDS_MUI_ERR_SAVEFILE "Erro salvando ""%s""" + IDS_MUI_ERR_PATHNOTFOUND "The path for ""%s"" no longer exists.\nRecreate the path and save the file?" IDS_MUI_ERR_DLG_FORMAT "Erro '%s', causa:\n%s(ID:%d)\n" IDS_MUI_ERR_BROWSE "Nenhum plugin de gerenciador de arquivos foi encontrado\nO plugin de gerenciador de arquivos MiniPath pode ser baixado de https://rizonesoft.com" IDS_MUI_ERR_GREPWIN "Nenhum plugin de localizador em arquivos foi encontrado\nO plugin de localizador em arquivos grepWinNP3 pode ser baixado de https://rizonesoft.com" diff --git a/language/np3_pt_pt/strings_pt_pt.rc b/language/np3_pt_pt/strings_pt_pt.rc index e0884766e..1bbf92504 100644 --- a/language/np3_pt_pt/strings_pt_pt.rc +++ b/language/np3_pt_pt/strings_pt_pt.rc @@ -129,6 +129,7 @@ STRINGTABLE BEGIN IDS_MUI_ERR_LOADFILE "Erro ao carregar ""%s""" IDS_MUI_ERR_SAVEFILE "Erro ao guardar ""%s""" + IDS_MUI_ERR_PATHNOTFOUND "The path for ""%s"" no longer exists.\nRecreate the path and save the file?" IDS_MUI_ERR_DLG_FORMAT "Erro '%s', causa:\n%s(ID:%d)\n" IDS_MUI_ERR_BROWSE "Não foi encontrado nenhum plugin de navegador de ficheiros\nO plugin do navegador de ficheiros MiniPath pode ser transferido de https://rizonesoft.com" IDS_MUI_ERR_GREPWIN "Não foi encontrado nenhum plugin de procura de ficheiros\nO plugin de procura de ficheiros grepWinNP3 pode ser transferido de https://rizonesoft.com" diff --git a/language/np3_ru_ru/strings_ru_ru.rc b/language/np3_ru_ru/strings_ru_ru.rc index 87b4cf641..25a61f34e 100644 --- a/language/np3_ru_ru/strings_ru_ru.rc +++ b/language/np3_ru_ru/strings_ru_ru.rc @@ -129,6 +129,7 @@ STRINGTABLE BEGIN IDS_MUI_ERR_LOADFILE "Ошибка загрузки «%s»" IDS_MUI_ERR_SAVEFILE "Ошибка сохранения «%s»" + IDS_MUI_ERR_PATHNOTFOUND "The path for ""%s"" no longer exists.\nRecreate the path and save the file?" IDS_MUI_ERR_DLG_FORMAT "Ошибка '%s', причина:\n%s(ID:%d)\n" IDS_MUI_ERR_BROWSE "Не найден плагин браузера файлов\nПлагин MiniPath можно загрузить с сайта https://rizonesoft.com" IDS_MUI_ERR_GREPWIN "Не найден плагин поиска в файлах\nПлагин grepWinNP3 можно загрузить с сайта https://rizonesoft.com" diff --git a/language/np3_sk_sk/strings_sk_sk.rc b/language/np3_sk_sk/strings_sk_sk.rc index 230eb1b9a..a59d203da 100644 --- a/language/np3_sk_sk/strings_sk_sk.rc +++ b/language/np3_sk_sk/strings_sk_sk.rc @@ -129,6 +129,7 @@ STRINGTABLE BEGIN IDS_MUI_ERR_LOADFILE "Chyba načítania ""%s""" IDS_MUI_ERR_SAVEFILE "Chyba ukladania ""%s""" + IDS_MUI_ERR_PATHNOTFOUND "The path for ""%s"" no longer exists.\nRecreate the path and save the file?" IDS_MUI_ERR_DLG_FORMAT "Chyba '%s', príčina:\n%s(ID:%d)\n" IDS_MUI_ERR_BROWSE "Nenašiel sa doplnok na prehľadávanie súborov\nDoplnok MiniPath si môžete stiahnuť z https://rizonesoft.com" IDS_MUI_ERR_GREPWIN "Nenašiel sa vyhľadávací doplnok\nDoplnok na vyhľadávanie súborov grepWinNP3 si môžete stiahnuť z https://rizonesoft.com" diff --git a/language/np3_sv_se/strings_sv_se.rc b/language/np3_sv_se/strings_sv_se.rc index ed49940df..49471cbdf 100644 --- a/language/np3_sv_se/strings_sv_se.rc +++ b/language/np3_sv_se/strings_sv_se.rc @@ -129,6 +129,7 @@ STRINGTABLE BEGIN IDS_MUI_ERR_LOADFILE "Fel vid laddning ""%s""" IDS_MUI_ERR_SAVEFILE "Fel vid sparande ""%s""" + IDS_MUI_ERR_PATHNOTFOUND "The path for ""%s"" no longer exists.\nRecreate the path and save the file?" IDS_MUI_ERR_DLG_FORMAT "Fel '%s', orsak:\n%s(ID:%d)\n" IDS_MUI_ERR_BROWSE "Inget plugin för filbläddring hittades\nMinipath filbläddrare kan laddas ner från https://rizonesoft.com" IDS_MUI_ERR_GREPWIN "Inget sökplugin hittades\ngrepWinNP3 filsökningsplugin kan hämtas från https://rizonesoft.com" diff --git a/language/np3_tr_tr/strings_tr_tr.rc b/language/np3_tr_tr/strings_tr_tr.rc index c5aaf44c1..ecb506627 100644 --- a/language/np3_tr_tr/strings_tr_tr.rc +++ b/language/np3_tr_tr/strings_tr_tr.rc @@ -129,6 +129,7 @@ STRINGTABLE BEGIN IDS_MUI_ERR_LOADFILE """%s"" yüklenirken sorun çıktı" IDS_MUI_ERR_SAVEFILE """%s"" kaydedilirken sorun çıktı" + IDS_MUI_ERR_PATHNOTFOUND "The path for ""%s"" no longer exists.\nRecreate the path and save the file?" IDS_MUI_ERR_DLG_FORMAT "Hata '%s'. Nedeni:\n%s(ID:%d)\n" IDS_MUI_ERR_BROWSE "Dosya gezgini uygulama eki bulunamadı\nMiniPath dosya tarayıcı uygulama ekini şuradan indirebilirsiniz: https://rizonesoft.com" IDS_MUI_ERR_GREPWIN "Dosya arama uygulama eki bulunamadı\ngrepWinNP3 dosya arama uygulama ekini şuradan indirebilirsiniz: https://rizonesoft.com" diff --git a/language/np3_vi_vn/strings_vi_vn.rc b/language/np3_vi_vn/strings_vi_vn.rc index 0968df454..209af3b2b 100644 --- a/language/np3_vi_vn/strings_vi_vn.rc +++ b/language/np3_vi_vn/strings_vi_vn.rc @@ -129,6 +129,7 @@ STRINGTABLE BEGIN IDS_MUI_ERR_LOADFILE "Đã xảy ra lỗi khi mở tệp ""%s""" IDS_MUI_ERR_SAVEFILE "Đã xảy ra lỗi khi lưu tệp ""%s""" + IDS_MUI_ERR_PATHNOTFOUND "The path for ""%s"" no longer exists.\nRecreate the path and save the file?" IDS_MUI_ERR_DLG_FORMAT "Lỗi '%s', Nguyên nhân:\n%s(ID:%d)\n" IDS_MUI_ERR_BROWSE "Không thể tìm thấy plugin trình duyệt tệp\nPlugin MiniPath có thể tải xuống từ https://rizonesoft.com" IDS_MUI_ERR_GREPWIN "Không thể tìm thấy plugin tìm kiếm tệp\nPlugin grepWinNP3 có thể tải xuống từ https://rizonesoft.com" diff --git a/language/np3_zh_cn/strings_zh_cn.rc b/language/np3_zh_cn/strings_zh_cn.rc index 8fffb6bdf..d75b6c42c 100644 --- a/language/np3_zh_cn/strings_zh_cn.rc +++ b/language/np3_zh_cn/strings_zh_cn.rc @@ -129,6 +129,7 @@ STRINGTABLE BEGIN IDS_MUI_ERR_LOADFILE "加载“%s”时遇到错误" IDS_MUI_ERR_SAVEFILE "保存“%s”时遇到错误" + IDS_MUI_ERR_PATHNOTFOUND "The path for ""%s"" no longer exists.\nRecreate the path and save the file?" IDS_MUI_ERR_DLG_FORMAT "错误“%s”,原因:\n%s(ID:%d)\n" IDS_MUI_ERR_BROWSE "无可用文件浏览器插件\n\nMiniPath 插件可以从 https://rizonesoft.com 下载" IDS_MUI_ERR_GREPWIN "无可用文件查找插件\n\ngrepWinNP3 插件可以从 https://rizonesoft.com 下载" diff --git a/language/np3_zh_tw/strings_zh_tw.rc b/language/np3_zh_tw/strings_zh_tw.rc index 1e532150f..b6b3ac096 100644 --- a/language/np3_zh_tw/strings_zh_tw.rc +++ b/language/np3_zh_tw/strings_zh_tw.rc @@ -129,6 +129,7 @@ STRINGTABLE BEGIN IDS_MUI_ERR_LOADFILE "載入 ""%s"" 時遇到錯誤" IDS_MUI_ERR_SAVEFILE "儲存 ""%"" 時遇到錯誤" + IDS_MUI_ERR_PATHNOTFOUND "The path for ""%s"" no longer exists.\nRecreate the path and save the file?" IDS_MUI_ERR_DLG_FORMAT "錯誤 ""%s"" ,原因:\n%s(ID:%d)\n" IDS_MUI_ERR_BROWSE "無可用檔案瀏覽器外掛\nMiniPath 外掛可由 https://rizonesoft.com 下載" IDS_MUI_ERR_GREPWIN "無可用檔案尋找外掛\ngrepWinNP3 外掛可由 https://rizonesoft.com 下載" diff --git a/src/Notepad3.c b/src/Notepad3.c index 633ac2d4b..3572013d7 100644 --- a/src/Notepad3.c +++ b/src/Notepad3.c @@ -11765,6 +11765,50 @@ bool FileSave(FileSaveFlags fSaveFlags) } } } + } else if (Globals.dwLastError == ERROR_PATH_NOT_FOUND) { + INT_PTR const answer = (Settings.MuteMessageBeep) ? + InfoBoxLng(MB_YESNO | MB_ICONWARNING, NULL, IDS_MUI_ERR_PATHNOTFOUND, currentFileName) : + MessageBoxLng(MB_YESNO | MB_ICONWARNING, IDS_MUI_ERR_PATHNOTFOUND, Path_Get(Paths.CurrentFile)); + if (IsYesOkay(answer)) { + // Recreate the directory tree (pattern from Config.cpp CreateIniFile) + HPATHL hdir_path = Path_Copy(Paths.CurrentFile); + Path_RemoveFileSpec(hdir_path); + bool bDirCreated = false; + if (Path_IsNotEmpty(hdir_path)) { + HRESULT const hr = SHCreateDirectoryExW(NULL, Path_Get(hdir_path), NULL); + bDirCreated = SUCCEEDED(hr) || (hr == HRESULT_FROM_WIN32(ERROR_ALREADY_EXISTS)); + } + Path_Release(hdir_path); + + if (bDirCreated) { + InstallFileWatching(false); + fSuccess = FileIO(false, Paths.CurrentFile, &fioStatus, FLF_None, FSF_EndSession, true); + if (fSuccess) { + if (!(fSaveFlags & FSF_SaveCopy) && !Flags.bDoRelaunchElevated) { + _MRU_AddSession(); + AddFilePathToRecentDocs(Paths.CurrentFile); + InstallFileWatching(true); + } else { + _MRU_UpdateSession(); + } + } else { + if (Settings.MuteMessageBeep) { + InfoBoxLng(MB_ICONERROR, NULL, IDS_MUI_ERR_SAVEFILE, currentFileName); + } else { + MessageBoxLng(MB_ICONERROR, IDS_MUI_ERR_SAVEFILE, Path_Get(Paths.CurrentFile)); + } + } + } else { + if (Settings.MuteMessageBeep) { + InfoBoxLng(MB_ICONERROR, NULL, IDS_MUI_ERR_SAVEFILE, currentFileName); + } else { + MessageBoxLng(MB_ICONERROR, IDS_MUI_ERR_SAVEFILE, Path_Get(Paths.CurrentFile)); + } + } + } else { + // User declined — offer Save As + FileSave(FSF_SaveAs); + } } else { if (Settings.MuteMessageBeep) { InfoBoxLng(MB_ICONERROR, NULL, IDS_MUI_ERR_SAVEFILE, currentFileName); diff --git a/todo/TODO.md b/todo/TODO.md index 3c479c6cb..cdc080d8b 100644 --- a/todo/TODO.md +++ b/todo/TODO.md @@ -22,7 +22,8 @@ - [x] **(Q1) BUG: /m command line uses last search mode** - ✅ FIXED - Issue: [#5060](https://github.com/rizonesoft/Notepad3/issues/5060) - Fix: When `/m` is used without 'R' flag, explicitly clear SCFIND_REGEXP to force text mode -- [ ] **(Q3) Replace GetOpenFileNameW with IFileOpenDialog** - Modern file dialog API +- [x] **(Q3) Replace GetOpenFileNameW with IFileOpenDialog** - Modern file dialog API + - [ ] **Test on Windows Server 2022 and higer** - Issues: [#5066](https://github.com/rizonesoft/Notepad3/issues/5066), [#5080](https://github.com/rizonesoft/Notepad3/issues/5080) - Fixes crash on Windows Server 2022 (STATUS_STACK_BUFFER_OVERRUN in ntdll.dll) - See [research/server2022-file-dialog-crash.md](research/server2022-file-dialog-crash.md) @@ -34,7 +35,7 @@ - CJK full-width replacement cached incorrectly - [ ] **(Q2) BUG: Initial window position not working** - Position settings ignored - Issue: [#4725](https://github.com/rizonesoft/Notepad3/issues/4725) -- [ ] **(Q3) BUG: Regex replace issue** - Verify if still present +- [x] **(Q3) BUG: Regex replace issue** - Verify if still present - ✅ FIXED - Issue: [#3531](https://github.com/rizonesoft/Notepad3/issues/3531) - Old bug from v5.21 - needs verification - [ ] **(Q2) BUG: Minipath options don't save** - FullRowSelect/TrackSelect broken @@ -59,9 +60,11 @@ - Fix: Forward `WM_SETTINGCHANGE` to Scintilla to refresh cached scroll parameters - [ ] **(Q2) BUG: Highlight current line broken** - Settings not respected (regression) - Issue: [#5270](https://github.com/rizonesoft/Notepad3/issues/5270) + - **This is a discussion, about limited line highlite rule language in schema definition ** - [ ] **(Q2) BUG: File lock held too long on save** - Blocks FileSystemWatcher - Issue: [#5301](https://github.com/rizonesoft/Notepad3/issues/5301) -- [ ] **(Q2) BUG: Folder handle leak** - Can't rename/delete folders with opened files +- [x] **(Q2) BUG: Folder handle leak** - Can't rename/delete folders with opened files + - [ ] **Needs testing** - Issue: [#5342](https://github.com/rizonesoft/Notepad3/issues/5342) - [x] **(Q1) BUG: Black line in Language menu** - ✅ FIXED - Issue: [#5361](https://github.com/rizonesoft/Notepad3/issues/5361)