Merge pull request #5884 from RaiKoHoff/dev_master

feat: Open Containing Folder (sel) and Open File from Selection
This commit is contained in:
Rainer Kottenhoff 2026-05-16 16:48:08 +02:00 committed by GitHub
commit f443e8807d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
33 changed files with 855 additions and 3 deletions

View File

@ -751,6 +751,8 @@
#define IDM_EDIT_COPY_MARKED 40392
#define IDM_EDIT_DELETE_MARKED 40393
#define IDM_EDIT_COPYRTF 40394
#define IDM_EDIT_OPEN_CONTAINING_FOLDER_SEL 40395
#define IDM_EDIT_OPEN_FILE_FROM_SEL 40396
#define IDM_VIEW_SCHEME 41001
#define IDM_VIEW_USE2NDDEFAULT 41002

View File

@ -317,6 +317,9 @@ BEGIN
MENUITEM "Kies &Woord of Lyne\tCtrl+Spc", IDM_EDIT_SELECTWORD
MENUITEM "Multi-Select &Alles wat Pas\tCtrl+Shift+Spc", IDM_EDIT_SELECTALLMATCHES
MENUITEM SEPARATOR
MENUITEM "Open &Containing Folder of Selection", IDM_EDIT_OPEN_CONTAINING_FOLDER_SEL
MENUITEM "Open &File from Selection", IDM_EDIT_OPEN_FILE_FROM_SEL
MENUITEM SEPARATOR
MENUITEM "Verdeel en Onttrek &Transaksies by Lynbrekings", IDM_VIEW_SPLIT_UNDOTYPSEQ_LNBRK
END
MENUITEM SEPARATOR
@ -596,6 +599,9 @@ BEGIN
MENUITEM SEPARATOR
MENUITEM "Web Sjabloon 1", CMD_WEBACTION1
MENUITEM "Web Sjabloon 2", CMD_WEBACTION2
MENUITEM SEPARATOR
MENUITEM "Open Containing Folder of Selection", IDM_EDIT_OPEN_CONTAINING_FOLDER_SEL
MENUITEM "Open File from Selection", IDM_EDIT_OPEN_FILE_FROM_SEL
MENUITEM "Maak File Explorer Oop", IDM_FILE_EXPLORE_DIR
END
POPUP "+"

View File

@ -317,6 +317,9 @@ BEGIN
MENUITEM "Вылучыць с&лова альбо радок\tCtrl+Spc", IDM_EDIT_SELECTWORD
MENUITEM "&Мультывылучэнне ўсіх уваходжанняў\tCtrl+Shift+Spc", IDM_EDIT_SELECTALLMATCHES
MENUITEM SEPARATOR
MENUITEM "Open &Containing Folder of Selection", IDM_EDIT_OPEN_CONTAINING_FOLDER_SEL
MENUITEM "Open &File from Selection", IDM_EDIT_OPEN_FILE_FROM_SEL
MENUITEM SEPARATOR
MENUITEM "Падзяліць &транзакцыю адмены па канчаткам радкоў", IDM_VIEW_SPLIT_UNDOTYPSEQ_LNBRK
END
MENUITEM SEPARATOR
@ -596,6 +599,9 @@ BEGIN
MENUITEM SEPARATOR
MENUITEM "Адкрыць вэб-дзеянне 1", CMD_WEBACTION1
MENUITEM "Адкрыць вэб-дзеянне 2", CMD_WEBACTION2
MENUITEM SEPARATOR
MENUITEM "Open Containing Folder of Selection", IDM_EDIT_OPEN_CONTAINING_FOLDER_SEL
MENUITEM "Open File from Selection", IDM_EDIT_OPEN_FILE_FROM_SEL
MENUITEM "Адкрыць Праваднік", IDM_FILE_EXPLORE_DIR
END
POPUP "+"

View File

@ -317,6 +317,9 @@ BEGIN
MENUITEM "Selektiere &Wort oder Zeile\tCtrl+Spc", IDM_EDIT_SELECTWORD
MENUITEM "Multiselektion &aller Fundstellen\tCtrl+Shift+Spc", IDM_EDIT_SELECTALLMATCHES
MENUITEM SEPARATOR
MENUITEM "Open &Containing Folder of Selection", IDM_EDIT_OPEN_CONTAINING_FOLDER_SEL
MENUITEM "Open &File from Selection", IDM_EDIT_OPEN_FILE_FROM_SEL
MENUITEM SEPARATOR
MENUITEM "Neue Undo &Transaktion bei Zeilenumbruch", IDM_VIEW_SPLIT_UNDOTYPSEQ_LNBRK
END
MENUITEM SEPARATOR
@ -596,6 +599,9 @@ BEGIN
MENUITEM SEPARATOR
MENUITEM "Öffne Web-Aktion 1", CMD_WEBACTION1
MENUITEM "Öffne Web Aktion 2", CMD_WEBACTION2
MENUITEM SEPARATOR
MENUITEM "Open Containing Folder of Selection", IDM_EDIT_OPEN_CONTAINING_FOLDER_SEL
MENUITEM "Open File from Selection", IDM_EDIT_OPEN_FILE_FROM_SEL
MENUITEM "Öffne Datei-Explorer", IDM_FILE_EXPLORE_DIR
END
POPUP "+"

View File

@ -317,6 +317,9 @@ BEGIN
MENUITEM "Επιλογή &λέξης ή γραμμών\tCtrl+Spc", IDM_EDIT_SELECTWORD
MENUITEM "Π&ολλαπλή επιλογή όλων των συμφωνιών\tCtrl+Shift+Spc", IDM_EDIT_SELECTALLMATCHES
MENUITEM SEPARATOR
MENUITEM "Open &Containing Folder of Selection", IDM_EDIT_OPEN_CONTAINING_FOLDER_SEL
MENUITEM "Open &File from Selection", IDM_EDIT_OPEN_FILE_FROM_SEL
MENUITEM SEPARATOR
MENUITEM "&Νέα λειτουργία αναίρεσης σε κάθε αλλαγή γραμμής", IDM_VIEW_SPLIT_UNDOTYPSEQ_LNBRK
END
MENUITEM SEPARATOR
@ -596,6 +599,9 @@ BEGIN
MENUITEM SEPARATOR
MENUITEM "Άνοιγμα ενέργειας Web 1", CMD_WEBACTION1
MENUITEM "Άνοιγμα ενέργειας Web 2", CMD_WEBACTION2
MENUITEM SEPARATOR
MENUITEM "Open Containing Folder of Selection", IDM_EDIT_OPEN_CONTAINING_FOLDER_SEL
MENUITEM "Open File from Selection", IDM_EDIT_OPEN_FILE_FROM_SEL
MENUITEM "Άνοιγμα Εξερεύνησης αρχείων", IDM_FILE_EXPLORE_DIR
END
POPUP "+"

View File

@ -317,6 +317,9 @@ BEGIN
MENUITEM "Select &Word or Lines\tCtrl+Spc", IDM_EDIT_SELECTWORD
MENUITEM "Multi-Select &All Matches\tCtrl+Shift+Spc", IDM_EDIT_SELECTALLMATCHES
MENUITEM SEPARATOR
MENUITEM "Open &Containing Folder of Selection", IDM_EDIT_OPEN_CONTAINING_FOLDER_SEL
MENUITEM "Open &File from Selection", IDM_EDIT_OPEN_FILE_FROM_SEL
MENUITEM SEPARATOR
MENUITEM "Split Undo &Transaction at Line-Breaks", IDM_VIEW_SPLIT_UNDOTYPSEQ_LNBRK
END
MENUITEM SEPARATOR
@ -596,6 +599,9 @@ BEGIN
MENUITEM SEPARATOR
MENUITEM "Open Web Action 1", CMD_WEBACTION1
MENUITEM "Open Web Action 2", CMD_WEBACTION2
MENUITEM SEPARATOR
MENUITEM "Open Containing Folder of Selection", IDM_EDIT_OPEN_CONTAINING_FOLDER_SEL
MENUITEM "Open File from Selection", IDM_EDIT_OPEN_FILE_FROM_SEL
MENUITEM "Open File Explorer", IDM_FILE_EXPLORE_DIR
END
POPUP "+"

View File

@ -317,6 +317,9 @@ BEGIN
MENUITEM "Select &Word or Lines\tCtrl+Spc", IDM_EDIT_SELECTWORD
MENUITEM "Multi-Select &All Matches\tCtrl+Shift+Spc", IDM_EDIT_SELECTALLMATCHES
MENUITEM SEPARATOR
MENUITEM "Open &Containing Folder of Selection", IDM_EDIT_OPEN_CONTAINING_FOLDER_SEL
MENUITEM "Open &File from Selection", IDM_EDIT_OPEN_FILE_FROM_SEL
MENUITEM SEPARATOR
MENUITEM "Split Undo &Transaction at Line-Breaks", IDM_VIEW_SPLIT_UNDOTYPSEQ_LNBRK
END
MENUITEM SEPARATOR
@ -596,6 +599,9 @@ BEGIN
MENUITEM SEPARATOR
MENUITEM "Open Web Action 1", CMD_WEBACTION1
MENUITEM "Open Web Action 2", CMD_WEBACTION2
MENUITEM SEPARATOR
MENUITEM "Open Containing Folder of Selection", IDM_EDIT_OPEN_CONTAINING_FOLDER_SEL
MENUITEM "Open File from Selection", IDM_EDIT_OPEN_FILE_FROM_SEL
MENUITEM "Open File Explorer", IDM_FILE_EXPLORE_DIR
END
POPUP "+"

View File

@ -317,6 +317,9 @@ BEGIN
MENUITEM "Seleccionar &palabra o líneas\tCtrl+Spc", IDM_EDIT_SELECTWORD
MENUITEM "Multi-selección &todas coincidencias\tCtrl+Shift+Spc", IDM_EDIT_SELECTALLMATCHES
MENUITEM SEPARATOR
MENUITEM "Open &Containing Folder of Selection", IDM_EDIT_OPEN_CONTAINING_FOLDER_SEL
MENUITEM "Open &File from Selection", IDM_EDIT_OPEN_FILE_FROM_SEL
MENUITEM SEPARATOR
MENUITEM "Dividir &transacción de deshacer en saltos de línea", IDM_VIEW_SPLIT_UNDOTYPSEQ_LNBRK
END
MENUITEM SEPARATOR
@ -596,6 +599,9 @@ BEGIN
MENUITEM SEPARATOR
MENUITEM "Abrir Web Acción 1", CMD_WEBACTION1
MENUITEM "Abrir Web Acción 2", CMD_WEBACTION2
MENUITEM SEPARATOR
MENUITEM "Open Containing Folder of Selection", IDM_EDIT_OPEN_CONTAINING_FOLDER_SEL
MENUITEM "Open File from Selection", IDM_EDIT_OPEN_FILE_FROM_SEL
MENUITEM "Abrir Explorador de archivos", IDM_FILE_EXPLORE_DIR
END
POPUP "+"

View File

@ -317,6 +317,9 @@ BEGIN
MENUITEM "Valitse &sana tai rivi\tCtrl+Spc", IDM_EDIT_SELECTWORD
MENUITEM "Monivalitse k&aikki täsmäävät\tCtrl+Shift+Spc", IDM_EDIT_SELECTALLMATCHES
MENUITEM SEPARATOR
MENUITEM "Open &Containing Folder of Selection", IDM_EDIT_OPEN_CONTAINING_FOLDER_SEL
MENUITEM "Open &File from Selection", IDM_EDIT_OPEN_FILE_FROM_SEL
MENUITEM SEPARATOR
MENUITEM "Jaa kumous&tapahtuma rivinvaihdon kohdalla", IDM_VIEW_SPLIT_UNDOTYPSEQ_LNBRK
END
MENUITEM SEPARATOR
@ -596,6 +599,9 @@ BEGIN
MENUITEM SEPARATOR
MENUITEM "Avaa verkkotoiminto 1", CMD_WEBACTION1
MENUITEM "Avaa verkkotoiminto 2", CMD_WEBACTION2
MENUITEM SEPARATOR
MENUITEM "Open Containing Folder of Selection", IDM_EDIT_OPEN_CONTAINING_FOLDER_SEL
MENUITEM "Open File from Selection", IDM_EDIT_OPEN_FILE_FROM_SEL
MENUITEM "Avaa tiedostonhallinta", IDM_FILE_EXPLORE_DIR
END
POPUP "+"

View File

@ -317,6 +317,9 @@ BEGIN
MENUITEM "Sélectionner le mot ou la ligne\tCtrl+Espac.", IDM_EDIT_SELECTWORD
MENUITEM "Multi-sélectionner toutes les correspond&ances\tCtrl+Maj+Espac.", IDM_EDIT_SELECTALLMATCHES
MENUITEM SEPARATOR
MENUITEM "Open &Containing Folder of Selection", IDM_EDIT_OPEN_CONTAINING_FOLDER_SEL
MENUITEM "Open &File from Selection", IDM_EDIT_OPEN_FILE_FROM_SEL
MENUITEM SEPARATOR
MENUITEM "Fractionner l'opération ""Défaire"" aux sauts de ligne", IDM_VIEW_SPLIT_UNDOTYPSEQ_LNBRK
END
MENUITEM SEPARATOR
@ -596,6 +599,9 @@ BEGIN
MENUITEM SEPARATOR
MENUITEM "Ouvrir Action Web &1", CMD_WEBACTION1
MENUITEM "Ouvrir Action Web &2", CMD_WEBACTION2
MENUITEM SEPARATOR
MENUITEM "Open Containing Folder of Selection", IDM_EDIT_OPEN_CONTAINING_FOLDER_SEL
MENUITEM "Open File from Selection", IDM_EDIT_OPEN_FILE_FROM_SEL
MENUITEM "Ouvrir l'Explorateur de fichiers", IDM_FILE_EXPLORE_DIR
END
POPUP "+"

View File

@ -317,6 +317,9 @@ BEGIN
MENUITEM "शब्द या रेखा चयनित करें (&W)\tCtrl+Spc", IDM_EDIT_SELECTWORD
MENUITEM "सारे मिलान बहु-चयनित करें (&A)\tCtrl+Shift+Spc", IDM_EDIT_SELECTALLMATCHES
MENUITEM SEPARATOR
MENUITEM "Open &Containing Folder of Selection", IDM_EDIT_OPEN_CONTAINING_FOLDER_SEL
MENUITEM "Open &File from Selection", IDM_EDIT_OPEN_FILE_FROM_SEL
MENUITEM SEPARATOR
MENUITEM "पंक्ति-विराम पर पूर्ववत लेनदेन विभाजित करें", IDM_VIEW_SPLIT_UNDOTYPSEQ_LNBRK
END
MENUITEM SEPARATOR
@ -596,6 +599,9 @@ BEGIN
MENUITEM SEPARATOR
MENUITEM "वेब प्रक्रिया 1 खोलें", CMD_WEBACTION1
MENUITEM "वेब प्रक्रिया 2 खोलें", CMD_WEBACTION2
MENUITEM SEPARATOR
MENUITEM "Open Containing Folder of Selection", IDM_EDIT_OPEN_CONTAINING_FOLDER_SEL
MENUITEM "Open File from Selection", IDM_EDIT_OPEN_FILE_FROM_SEL
MENUITEM "फ़ाइल एक्स्प्लोरर खोलें", IDM_FILE_EXPLORE_DIR
END
POPUP "+"

View File

@ -317,6 +317,9 @@ BEGIN
MENUITEM "Szó vag&y sorok kijelölése\tCtrl+Spc", IDM_EDIT_SELECTWORD
MENUITEM "Összes egyezés ki&jelölése\tCtrl+Shift+Spc", IDM_EDIT_SELECTALLMATCHES
MENUITEM SEPARATOR
MENUITEM "Open &Containing Folder of Selection", IDM_EDIT_OPEN_CONTAINING_FOLDER_SEL
MENUITEM "Open &File from Selection", IDM_EDIT_OPEN_FILE_FROM_SEL
MENUITEM SEPARATOR
MENUITEM "Visszavonás műveletek szétvágása sortöréseknél", IDM_VIEW_SPLIT_UNDOTYPSEQ_LNBRK
END
MENUITEM SEPARATOR
@ -596,6 +599,9 @@ BEGIN
MENUITEM SEPARATOR
MENUITEM "Webes művelet 1", CMD_WEBACTION1
MENUITEM "Webes művelet 2", CMD_WEBACTION2
MENUITEM SEPARATOR
MENUITEM "Open Containing Folder of Selection", IDM_EDIT_OPEN_CONTAINING_FOLDER_SEL
MENUITEM "Open File from Selection", IDM_EDIT_OPEN_FILE_FROM_SEL
MENUITEM "Fájlböngésző megnyitása", IDM_FILE_EXPLORE_DIR
END
POPUP "+"

View File

@ -317,6 +317,9 @@ BEGIN
MENUITEM "Pilih Kata a&tau Baris\tCtrl+Spc", IDM_EDIT_SELECTWORD
MENUITEM "Pilih Semua yang &Sesuai\tCtrl+Shift+Spc", IDM_EDIT_SELECTALLMATCHES
MENUITEM SEPARATOR
MENUITEM "Open &Containing Folder of Selection", IDM_EDIT_OPEN_CONTAINING_FOLDER_SEL
MENUITEM "Open &File from Selection", IDM_EDIT_OPEN_FILE_FROM_SEL
MENUITEM SEPARATOR
MENUITEM "Pisahkan &Riwayat Kembali pada Baris Baru", IDM_VIEW_SPLIT_UNDOTYPSEQ_LNBRK
END
MENUITEM SEPARATOR
@ -596,6 +599,9 @@ BEGIN
MENUITEM SEPARATOR
MENUITEM "Buka Aksi Web 1", CMD_WEBACTION1
MENUITEM "Buka Aksi Web 2", CMD_WEBACTION2
MENUITEM SEPARATOR
MENUITEM "Open Containing Folder of Selection", IDM_EDIT_OPEN_CONTAINING_FOLDER_SEL
MENUITEM "Open File from Selection", IDM_EDIT_OPEN_FILE_FROM_SEL
MENUITEM "Buka File Explorer", IDM_FILE_EXPLORE_DIR
END
POPUP "+"

View File

@ -317,6 +317,9 @@ BEGIN
MENUITEM "Seleziona &parola o linea\tCtrl+Spc", IDM_EDIT_SELECTWORD
MENUITEM "Multi selezione di &tutte le occorrenze\tCtrl+Maiusc+Spazio", IDM_EDIT_SELECTALLMATCHES
MENUITEM SEPARATOR
MENUITEM "Open &Containing Folder of Selection", IDM_EDIT_OPEN_CONTAINING_FOLDER_SEL
MENUITEM "Open &File from Selection", IDM_EDIT_OPEN_FILE_FROM_SEL
MENUITEM SEPARATOR
MENUITEM "Separa &transazione annulla azione per ogni linea", IDM_VIEW_SPLIT_UNDOTYPSEQ_LNBRK
END
MENUITEM SEPARATOR
@ -596,6 +599,9 @@ BEGIN
MENUITEM SEPARATOR
MENUITEM "Apri azione web 1", CMD_WEBACTION1
MENUITEM "Apri azione web 2", CMD_WEBACTION2
MENUITEM SEPARATOR
MENUITEM "Open Containing Folder of Selection", IDM_EDIT_OPEN_CONTAINING_FOLDER_SEL
MENUITEM "Open File from Selection", IDM_EDIT_OPEN_FILE_FROM_SEL
MENUITEM "Apri Esplora File", IDM_FILE_EXPLORE_DIR
END
POPUP "+"

View File

@ -317,6 +317,9 @@ BEGIN
MENUITEM "単語や行を選択(&W)\tCtrl+Spc", IDM_EDIT_SELECTWORD
MENUITEM "一致文字列すべてに複数カーソル(&A)\tCtrl+Shift+Spc", IDM_EDIT_SELECTALLMATCHES
MENUITEM SEPARATOR
MENUITEM "Open &Containing Folder of Selection", IDM_EDIT_OPEN_CONTAINING_FOLDER_SEL
MENUITEM "Open &File from Selection", IDM_EDIT_OPEN_FILE_FROM_SEL
MENUITEM SEPARATOR
MENUITEM "「元に戻す」の履歴を改行で区切る(&T)", IDM_VIEW_SPLIT_UNDOTYPSEQ_LNBRK
END
MENUITEM SEPARATOR
@ -596,6 +599,9 @@ BEGIN
MENUITEM SEPARATOR
MENUITEM "ウェブ1で開く", CMD_WEBACTION1
MENUITEM "ウェブ2で開く", CMD_WEBACTION2
MENUITEM SEPARATOR
MENUITEM "Open Containing Folder of Selection", IDM_EDIT_OPEN_CONTAINING_FOLDER_SEL
MENUITEM "Open File from Selection", IDM_EDIT_OPEN_FILE_FROM_SEL
MENUITEM "エクスプローラーを開く", IDM_FILE_EXPLORE_DIR
END
POPUP "+"

View File

@ -317,6 +317,9 @@ BEGIN
MENUITEM "단어 또는 줄 선택(&W)\tCtrl+Spc", IDM_EDIT_SELECTWORD
MENUITEM "모든 일치 다중 선택(&A)\tCtrl+Shift+Spc", IDM_EDIT_SELECTALLMATCHES
MENUITEM SEPARATOR
MENUITEM "Open &Containing Folder of Selection", IDM_EDIT_OPEN_CONTAINING_FOLDER_SEL
MENUITEM "Open &File from Selection", IDM_EDIT_OPEN_FILE_FROM_SEL
MENUITEM SEPARATOR
MENUITEM "줄 바꿈에서 분할 실행 취소 처리(&T)", IDM_VIEW_SPLIT_UNDOTYPSEQ_LNBRK
END
MENUITEM SEPARATOR
@ -596,6 +599,9 @@ BEGIN
MENUITEM SEPARATOR
MENUITEM "웹 작업 1 열기", CMD_WEBACTION1
MENUITEM "웹 작업 2 열기", CMD_WEBACTION2
MENUITEM SEPARATOR
MENUITEM "Open Containing Folder of Selection", IDM_EDIT_OPEN_CONTAINING_FOLDER_SEL
MENUITEM "Open File from Selection", IDM_EDIT_OPEN_FILE_FROM_SEL
MENUITEM "파일 탐색기 열기", IDM_FILE_EXPLORE_DIR
END
POPUP "+"

View File

@ -317,6 +317,9 @@ BEGIN
MENUITEM "&Woord of regel(s) selecteren\tCtrl+Spc", IDM_EDIT_SELECTWORD
MENUITEM "&Alle overeenkomsten selecteren\tCtrl+Shift+Spc", IDM_EDIT_SELECTALLMATCHES
MENUITEM SEPARATOR
MENUITEM "Open &Containing Folder of Selection", IDM_EDIT_OPEN_CONTAINING_FOLDER_SEL
MENUITEM "Open &File from Selection", IDM_EDIT_OPEN_FILE_FROM_SEL
MENUITEM SEPARATOR
MENUITEM "&Ongedaan maken bij regeleinde afbreken", IDM_VIEW_SPLIT_UNDOTYPSEQ_LNBRK
END
MENUITEM SEPARATOR
@ -596,6 +599,9 @@ BEGIN
MENUITEM SEPARATOR
MENUITEM "Websjabloon 1 openen", CMD_WEBACTION1
MENUITEM "Websjabloon 2 openen", CMD_WEBACTION2
MENUITEM SEPARATOR
MENUITEM "Open Containing Folder of Selection", IDM_EDIT_OPEN_CONTAINING_FOLDER_SEL
MENUITEM "Open File from Selection", IDM_EDIT_OPEN_FILE_FROM_SEL
MENUITEM "MiniPath verkenner openen", IDM_FILE_EXPLORE_DIR
END
POPUP "+"

View File

@ -317,6 +317,9 @@ BEGIN
MENUITEM "Zaznacz wyraz lub wiersz\tCtrl+Spc", IDM_EDIT_SELECTWORD
MENUITEM "Multiwybór-wszystko pasujące\tCtrl+Shift+Spc", IDM_EDIT_SELECTALLMATCHES
MENUITEM SEPARATOR
MENUITEM "Open &Containing Folder of Selection", IDM_EDIT_OPEN_CONTAINING_FOLDER_SEL
MENUITEM "Open &File from Selection", IDM_EDIT_OPEN_FILE_FROM_SEL
MENUITEM SEPARATOR
MENUITEM "Podział operacji cofania przy przenoszeniu wierszy", IDM_VIEW_SPLIT_UNDOTYPSEQ_LNBRK
END
MENUITEM SEPARATOR
@ -596,6 +599,9 @@ BEGIN
MENUITEM SEPARATOR
MENUITEM "Otwórz Web Action 1", CMD_WEBACTION1
MENUITEM "Otwórz Web Action 2", CMD_WEBACTION2
MENUITEM SEPARATOR
MENUITEM "Open Containing Folder of Selection", IDM_EDIT_OPEN_CONTAINING_FOLDER_SEL
MENUITEM "Open File from Selection", IDM_EDIT_OPEN_FILE_FROM_SEL
MENUITEM "Otwórz Eksplorator plików", IDM_FILE_EXPLORE_DIR
END
POPUP "+"

View File

@ -317,6 +317,9 @@ BEGIN
MENUITEM "Selecionar &Palavras ou Linhas\tCtrl+Spc", IDM_EDIT_SELECTWORD
MENUITEM "Multi-Seleção de &Todos os Casados\tCtrl+Shift+Spc", IDM_EDIT_SELECTALLMATCHES
MENUITEM SEPARATOR
MENUITEM "Open &Containing Folder of Selection", IDM_EDIT_OPEN_CONTAINING_FOLDER_SEL
MENUITEM "Open &File from Selection", IDM_EDIT_OPEN_FILE_FROM_SEL
MENUITEM SEPARATOR
MENUITEM "Dividir &Transações Desfeitas nas Quebras de Linha", IDM_VIEW_SPLIT_UNDOTYPSEQ_LNBRK
END
MENUITEM SEPARATOR
@ -596,6 +599,9 @@ BEGIN
MENUITEM SEPARATOR
MENUITEM "Abrir Ação Web 1", CMD_WEBACTION1
MENUITEM "Abrir Ação Web 2", CMD_WEBACTION2
MENUITEM SEPARATOR
MENUITEM "Open Containing Folder of Selection", IDM_EDIT_OPEN_CONTAINING_FOLDER_SEL
MENUITEM "Open File from Selection", IDM_EDIT_OPEN_FILE_FROM_SEL
MENUITEM "Abri Gerenciador de Arquivos", IDM_FILE_EXPLORE_DIR
END
POPUP "+"

View File

@ -317,6 +317,9 @@ BEGIN
MENUITEM "Seleccionar &palavra ou linhas\tCtrl+Spc", IDM_EDIT_SELECTWORD
MENUITEM "Multi-Seleccionar tod&as as correspondências\tCtrl+Shift+Spc", IDM_EDIT_SELECTALLMATCHES
MENUITEM SEPARATOR
MENUITEM "Open &Containing Folder of Selection", IDM_EDIT_OPEN_CONTAINING_FOLDER_SEL
MENUITEM "Open &File from Selection", IDM_EDIT_OPEN_FILE_FROM_SEL
MENUITEM SEPARATOR
MENUITEM "Dividir &transacção anular nas quebras de linha", IDM_VIEW_SPLIT_UNDOTYPSEQ_LNBRK
END
MENUITEM SEPARATOR
@ -596,6 +599,9 @@ BEGIN
MENUITEM SEPARATOR
MENUITEM "Abrir acção Web 1", CMD_WEBACTION1
MENUITEM "Abrir acção Web 2", CMD_WEBACTION2
MENUITEM SEPARATOR
MENUITEM "Open Containing Folder of Selection", IDM_EDIT_OPEN_CONTAINING_FOLDER_SEL
MENUITEM "Open File from Selection", IDM_EDIT_OPEN_FILE_FROM_SEL
MENUITEM "Abrir Explorador de ficheiros", IDM_FILE_EXPLORE_DIR
END
POPUP "+"

View File

@ -317,6 +317,9 @@ BEGIN
MENUITEM "Выбрать с&лово или строку\tCtrl+Spc", IDM_EDIT_SELECTWORD
MENUITEM "&Мультивыбор всех совпадений\tCtrl+Shift+Spc", IDM_EDIT_SELECTALLMATCHES
MENUITEM SEPARATOR
MENUITEM "Open &Containing Folder of Selection", IDM_EDIT_OPEN_CONTAINING_FOLDER_SEL
MENUITEM "Open &File from Selection", IDM_EDIT_OPEN_FILE_FROM_SEL
MENUITEM SEPARATOR
MENUITEM "Разделить &транзакцию отмены по окончаниям строк", IDM_VIEW_SPLIT_UNDOTYPSEQ_LNBRK
END
MENUITEM SEPARATOR
@ -596,6 +599,9 @@ BEGIN
MENUITEM SEPARATOR
MENUITEM "Открыть веб-действие 1", CMD_WEBACTION1
MENUITEM "Открыть веб-действие 2", CMD_WEBACTION2
MENUITEM SEPARATOR
MENUITEM "Open Containing Folder of Selection", IDM_EDIT_OPEN_CONTAINING_FOLDER_SEL
MENUITEM "Open File from Selection", IDM_EDIT_OPEN_FILE_FROM_SEL
MENUITEM "Открыть Проводник", IDM_FILE_EXPLORE_DIR
END
POPUP "+"

View File

@ -317,6 +317,9 @@ BEGIN
MENUITEM "Vybrať &slovo alebo riadok\tCtrl+Spc", IDM_EDIT_SELECTWORD
MENUITEM "&Viacnásobný výber všetkých zhôd\tCtrl+Shift+Spc", IDM_EDIT_SELECTALLMATCHES
MENUITEM SEPARATOR
MENUITEM "Open &Containing Folder of Selection", IDM_EDIT_OPEN_CONTAINING_FOLDER_SEL
MENUITEM "Open &File from Selection", IDM_EDIT_OPEN_FILE_FROM_SEL
MENUITEM SEPARATOR
MENUITEM "Rozdeliť a&kciu Späť po zalomení riadku", IDM_VIEW_SPLIT_UNDOTYPSEQ_LNBRK
END
MENUITEM SEPARATOR
@ -596,6 +599,9 @@ BEGIN
MENUITEM SEPARATOR
MENUITEM "Webová šablóna 1", CMD_WEBACTION1
MENUITEM "Webová šablóna 2", CMD_WEBACTION2
MENUITEM SEPARATOR
MENUITEM "Open Containing Folder of Selection", IDM_EDIT_OPEN_CONTAINING_FOLDER_SEL
MENUITEM "Open File from Selection", IDM_EDIT_OPEN_FILE_FROM_SEL
MENUITEM "Otvoriť Prieskumníka", IDM_FILE_EXPLORE_DIR
END
POPUP "+"

View File

@ -317,6 +317,9 @@ BEGIN
MENUITEM "Markera ord eller rader\tCtrl+Spc", IDM_EDIT_SELECTWORD
MENUITEM "Markera alla matchningar\tCtrl+Shift+Spc", IDM_EDIT_SELECTALLMATCHES
MENUITEM SEPARATOR
MENUITEM "Open &Containing Folder of Selection", IDM_EDIT_OPEN_CONTAINING_FOLDER_SEL
MENUITEM "Open &File from Selection", IDM_EDIT_OPEN_FILE_FROM_SEL
MENUITEM SEPARATOR
MENUITEM "Dela ångra vid radslut", IDM_VIEW_SPLIT_UNDOTYPSEQ_LNBRK
END
MENUITEM SEPARATOR
@ -596,6 +599,9 @@ BEGIN
MENUITEM SEPARATOR
MENUITEM "Öppna webbåtgärd 1", CMD_WEBACTION1
MENUITEM "Öppna webbåtgärd 2", CMD_WEBACTION2
MENUITEM SEPARATOR
MENUITEM "Open Containing Folder of Selection", IDM_EDIT_OPEN_CONTAINING_FOLDER_SEL
MENUITEM "Open File from Selection", IDM_EDIT_OPEN_FILE_FROM_SEL
MENUITEM "Öppna Utforskaren", IDM_FILE_EXPLORE_DIR
END
POPUP "+"

View File

@ -317,6 +317,9 @@ BEGIN
MENUITEM "Sözcük &ya da satır seç\tCtrl+Spc", IDM_EDIT_SELECTWORD
MENUITEM "&Tüm eşleşmeleri seç\tCtrl+Shift+Spc", IDM_EDIT_SELECTALLMATCHES
MENUITEM SEPARATOR
MENUITEM "Open &Containing Folder of Selection", IDM_EDIT_OPEN_CONTAINING_FOLDER_SEL
MENUITEM "Open &File from Selection", IDM_EDIT_OPEN_FILE_FROM_SEL
MENUITEM SEPARATOR
MENUITEM "Satır sonlarında &geri alma işlemini ayır", IDM_VIEW_SPLIT_UNDOTYPSEQ_LNBRK
END
MENUITEM SEPARATOR
@ -596,6 +599,9 @@ BEGIN
MENUITEM SEPARATOR
MENUITEM "1. web işlemini aç", CMD_WEBACTION1
MENUITEM "2. web işlemini aç", CMD_WEBACTION2
MENUITEM SEPARATOR
MENUITEM "Open Containing Folder of Selection", IDM_EDIT_OPEN_CONTAINING_FOLDER_SEL
MENUITEM "Open File from Selection", IDM_EDIT_OPEN_FILE_FROM_SEL
MENUITEM "Dosya gezginini aç", IDM_FILE_EXPLORE_DIR
END
POPUP "+"

View File

@ -317,6 +317,9 @@ BEGIN
MENUITEM "Chọn từ hoặc dòng(&W)\tCtrl+Spc", IDM_EDIT_SELECTWORD
MENUITEM "Chọn tất cả khớp(&A)\tCtrl+Shift+Spc", IDM_EDIT_SELECTALLMATCHES
MENUITEM SEPARATOR
MENUITEM "Open &Containing Folder of Selection", IDM_EDIT_OPEN_CONTAINING_FOLDER_SEL
MENUITEM "Open &File from Selection", IDM_EDIT_OPEN_FILE_FROM_SEL
MENUITEM SEPARATOR
MENUITEM "Xử lý Undo khi phân chia tại dòng(&T)", IDM_VIEW_SPLIT_UNDOTYPSEQ_LNBRK
END
MENUITEM SEPARATOR
@ -596,6 +599,9 @@ BEGIN
MENUITEM SEPARATOR
MENUITEM "Mở tác vụ web 1", CMD_WEBACTION1
MENUITEM "Mở tác vụ web 2", CMD_WEBACTION2
MENUITEM SEPARATOR
MENUITEM "Open Containing Folder of Selection", IDM_EDIT_OPEN_CONTAINING_FOLDER_SEL
MENUITEM "Open File from Selection", IDM_EDIT_OPEN_FILE_FROM_SEL
MENUITEM "Mở Explorer", IDM_FILE_EXPLORE_DIR
END
POPUP "+"

View File

@ -317,6 +317,9 @@ BEGIN
MENUITEM "选定单词或行(&W)\tCtrl+Spc", IDM_EDIT_SELECTWORD
MENUITEM "选定全部匹配(&A)\tCtrl+Shift+Spc", IDM_EDIT_SELECTALLMATCHES
MENUITEM SEPARATOR
MENUITEM "Open &Containing Folder of Selection", IDM_EDIT_OPEN_CONTAINING_FOLDER_SEL
MENUITEM "Open &File from Selection", IDM_EDIT_OPEN_FILE_FROM_SEL
MENUITEM SEPARATOR
MENUITEM "换行时重定撤销操作边界(&T)", IDM_VIEW_SPLIT_UNDOTYPSEQ_LNBRK
END
MENUITEM SEPARATOR
@ -596,6 +599,9 @@ BEGIN
MENUITEM SEPARATOR
MENUITEM "用超链接模板 1 打开", CMD_WEBACTION1
MENUITEM "用超链接模板 2 打开", CMD_WEBACTION2
MENUITEM SEPARATOR
MENUITEM "Open Containing Folder of Selection", IDM_EDIT_OPEN_CONTAINING_FOLDER_SEL
MENUITEM "Open File from Selection", IDM_EDIT_OPEN_FILE_FROM_SEL
MENUITEM "打开资源管理器", IDM_FILE_EXPLORE_DIR
END
POPUP "+"

View File

@ -317,6 +317,9 @@ BEGIN
MENUITEM "選定單詞或行(&W)\tCtrl+Spc", IDM_EDIT_SELECTWORD
MENUITEM "選定全部符合(&A)\tCtrl+Shift+Spc", IDM_EDIT_SELECTALLMATCHES
MENUITEM SEPARATOR
MENUITEM "Open &Containing Folder of Selection", IDM_EDIT_OPEN_CONTAINING_FOLDER_SEL
MENUITEM "Open &File from Selection", IDM_EDIT_OPEN_FILE_FROM_SEL
MENUITEM SEPARATOR
MENUITEM "換行時重定復原操作邊界(&T)", IDM_VIEW_SPLIT_UNDOTYPSEQ_LNBRK
END
MENUITEM SEPARATOR
@ -596,6 +599,9 @@ BEGIN
MENUITEM SEPARATOR
MENUITEM "用超連結模板 1 打開", CMD_WEBACTION1
MENUITEM "用超連結模板 2 打開", CMD_WEBACTION2
MENUITEM SEPARATOR
MENUITEM "Open Containing Folder of Selection", IDM_EDIT_OPEN_CONTAINING_FOLDER_SEL
MENUITEM "Open File from Selection", IDM_EDIT_OPEN_FILE_FROM_SEL
MENUITEM "打開檔案總管", IDM_FILE_EXPLORE_DIR
END
POPUP "+"

226
plans/explore_file_refs.md Normal file
View File

@ -0,0 +1,226 @@
# Plan — Follow-up enhancements: file/path reference handling
Companion to the now-shipped change that added `IDM_EDIT_OPEN_CONTAINING_FOLDER_SEL` / `IDM_EDIT_OPEN_FILE_FROM_SEL` and fixed the `Paths.ModuleDirectory` anchor bug in the hyperlink-click handler.
These items were intentionally deferred from that change to keep the scope tight. They are independent of each other; pick any subset.
## Status (2026-05-16)
Already shipped on `dev_master`:
- New selection-based commands `IDM_EDIT_OPEN_CONTAINING_FOLDER_SEL` (40395) and `IDM_EDIT_OPEN_FILE_FROM_SEL` (40396), wired to Edit > Miscellaneous and the editor right-click popup. No accelerator — users can bind one via custom keybindings if desired.
- Shared helpers in `src\Helpers.c`: `ExtractSelectionOrTokenAtCaret`, `SplitFilePathLineColNum`, `ResolveSelectionToPath`.
- Bug fix at `src\Notepad3.c:8891` (or thereabouts after later edits) — relative `file:///` URLs now anchor to the current document's directory, fallback `Paths.WorkingDirectory`, never `Paths.ModuleDirectory`.
- English placeholder strings replicated across all 25 sibling locale `menu_*.rc` files. Translators still need to translate them.
Function bodies for the two new commands live in `src\Notepad3.c` (not Edit.c) because `<shlobj.h>` defines `SORT_ASCENDING` / `SORT_DESCENDING` enum values that conflict with Edit.c's `SortOrderMask` enum.
## Item 1 — Bare-path hotspotting (`HYPLNK_REGEX_FULL` extension)
**Goal**: make `C:\Users\me\foo.txt`, `\\server\share\file`, `.\rel\path.c`, `../include/foo.h`, and similar bare paths clickable hotspots in the editor, just like `https://...` URLs already are.
### Why this is deferred and load-bearing
The existing hyperlink hotspot system (`src\Edit.c:111-116`) uses one big PCRE2 regex that requires an explicit scheme prefix:
```c
#define HYPLNK_REGEX_FULL "\\b(?:(?:https?|ftp)://|file:///|file://|mailto:|www\\.|ftp\\.)" ...
```
Adding bare-path matching is high-risk because:
1. **False positives**`C:` could match in non-path text (e.g. a code snippet, a colon-time `12:34:56`).
2. **Indicator-marking pass cost** — the URL hotspotter runs on every restyle (`MarkAllOccurrences` flow). A broader regex adds CPU per keystroke in large documents.
3. **Lexer interference** — many lexers already style strings/paths in domain-specific ways. Adding `INDIC_NP3_HYPERLINK` on top of an existing lexer style can cause visual conflicts (double-underlining, color clash).
4. **`SCN_INDICATORRELEASE` activation** — currently `HandleHotSpotURLClicked` at `src\Notepad3.c:8824` is dispatched on indicator-release. It calls `UrlIsFileUrl(szTextW)` to decide between OPEN_IN_NOTEPAD3 and OPEN_WITH_BROWSER. Bare paths aren't file:// URLs, so the routing logic needs a new branch: "if it looks like a Windows path, treat it as OPEN_IN_NOTEPAD3 directly."
### Implementation sketch
Two viable approaches:
**A. Single bigger regex.** Add an alternation arm for paths. E.g.:
```
\\b(?:[A-Za-z]:[\\\\/]|\\\\\\\\[^\\s]+\\\\|\\.{1,2}[\\\\/])[^\\s'`"<>|*,;]+
```
- Drive-letter: `C:\...`, `c:/...`
- UNC: `\\server\share\...`
- Relative: `.\foo`, `..\foo`, `./foo`, `../foo`
Pros: minimal code change. Cons: regex becomes harder to maintain; false-positive risk is concentrated.
**B. Second-pass detection.** Keep `HYPLNK_REGEX_FULL` for scheme URLs. Add a separate, more restrictive pass for bare paths only when the line context suggests "this is a path" — e.g. preceded by `at`, `file:`, `> `, in compiler-error format `file.c:42:`, etc. More conservative; harder to author.
**Recommendation**: try (A) but gate behind a `Settings2.HyperlinkBarePaths` opt-in toggle defaulting to `false`. Document the toggle in `Build\Notepad3.ini` `[Settings2]` and `readme/config/Configuration.md` (CLAUDE.md invariant).
### Required touchpoints
| File | Change |
|---|---|
| `src\Edit.c:111-116` | Extend `HYPLNK_REGEX_FULL` (or add `HYPLNK_REGEX_BAREPATH` and run both) |
| `src\Notepad3.c:8824` (`HandleHotSpotURLClicked`) | New branch when `!UrlIsFileUrl(szTextW)` AND text looks like a Windows path → call same OPEN_IN_NOTEPAD3 logic but skip `PathCreateFromUrlW` (use the text as-is, then `ResolveSelectionToPath`-style anchoring) |
| `src\TypeDefs.h` (`Settings2`) | Add `HyperlinkBarePaths` bool with default `false` |
| `src\Config\Config.cpp` | Persist `HyperlinkBarePaths` |
| `Build\Notepad3.ini`, `readme\config\Configuration.md` | Document new INI key |
### Verification
- Open a fresh `.txt` buffer with toggle ON. Paste:
```
C:\Windows\notepad.exe
..\src\Helpers.c
\\?\C:\Windows
src/Edit.c:111
See line C: this should NOT highlight
Time 12:34:56 must NOT highlight
```
Expect: lines 1-4 hotspotted, lines 5-6 not.
- With toggle OFF: no change vs. current behavior.
- Test in C/C++ buffer (SCLEX_CPP) to confirm no lexer-style clash on strings containing paths.
## Item 2 — Markdown `[label](url)` extraction in `ExtractSelectionOrTokenAtCaret`
**Goal**: when the caret is inside the URL portion of a Markdown link `[label](url)`, the selection extractor should grab `url` rather than expanding outward through the closing `)` and stopping at the next whitespace.
### Why this is deferred
The current `ExtractSelectionOrTokenAtCaret` in `src\Helpers.c` uses a flat boundary set `[\s'`"<>|*,;]` and never considers paired-delimiter context. Notepad4's `EditGetStringAroundCaret` (`notepad4\src\Edit.cpp:7015-7093`) has a dedicated subroutine to recognize `(...)` after a Markdown link target and clamp the extraction.
It's deferred because: (a) Notepad3 already hotspots Markdown URLs via the lexer-driven indicator path, so most Markdown click flows already work; (b) the extractor is used by the new selection commands, where the user can always select the URL by hand if the auto-expand is wrong.
### Sketch
Inside `ExtractSelectionOrTokenAtCaret` in `src\Helpers.c`, when the selection is empty, BEFORE the regular boundary scan:
```c
// Markdown link target: if caret sits inside `(...)` and the char before '(' is ']',
// clamp the extraction to the contents of the parens.
DocPos const posCur = SciCall_GetCurrentPos();
// Walk back to find an unmatched '(' on the same line.
// If found AND the char immediately before is ']', use [openParen+1, matching ')') as the span.
```
Use Scintilla's bracket-matching (`SciCall_BraceMatch`) — but only on `(`; Scintilla supports `()` `[]` `{}` `<>`. Caveat: caret-on-`(` semantics vary; you may need to do a manual scan.
### Touchpoints
- `src\Helpers.c``ExtractSelectionOrTokenAtCaret` (introduced in the prior change).
### Verification
```markdown
See [the doc](D:\projects\foo\readme.md) for details.
^ caret here
```
Invoke "Open File from Selection" → opens `D:\projects\foo\readme.md`. Currently expands to `D:\projects\foo\readme.md)` and the trailing `)` may or may not be tolerated by `ResolveSelectionToPath`.
## Item 3 — Enable/disable gating in `MsgInitMenu` for the new commands
**Goal**: grey out `IDM_EDIT_OPEN_CONTAINING_FOLDER_SEL` / `IDM_EDIT_OPEN_FILE_FROM_SEL` when there's no selection AND no token at the caret position.
### Current behavior
The commands are always enabled. Invoking them with an empty selection on whitespace-only content silently produces a `MessageBeep(MB_ICONHAND)`. This matches Notepad4's UX and is acceptable, but a power user might prefer a greyed-out menu.
### Sketch
`MsgInitMenu()` in `src\Notepad3.c` should add (near the existing `IDM_EDIT_INSERT_GUID` enable check around line 4963):
```c
bool const bHasToken = !SciCall_IsSelectionEmpty();
// optionally also check word boundaries at SciCall_GetCurrentPos()
EnableCmd(hmenu, IDM_EDIT_OPEN_CONTAINING_FOLDER_SEL, bHasToken /* OR token-at-caret */);
EnableCmd(hmenu, IDM_EDIT_OPEN_FILE_FROM_SEL, bHasToken);
```
Right-click context menu builder at `src\Notepad3.c:4549` (`imenu == MNU_EDIT` branch) already has a similar pattern for the case-conversion commands using `s_iCtxMenuClickPos`. Add the same predicate there.
### Verification
- Empty selection, caret on whitespace → menu items greyed.
- Empty selection, caret in a word → enabled.
- Any non-empty selection → enabled.
## Item 4 — `\\?\` long-path prefix handling in `ResolveSelectionToPath`
**Goal**: gracefully handle paths with the Windows long-path prefix when passed to `SHParseDisplayName`.
### Why
`SHParseDisplayName` does not always accept `\\?\C:\...`. For shell-API consumption the prefix should be stripped. PathLib wrappers already handle this internally for filesystem ops, but `EditOpenContainingFolderFromSelection` calls `SHParseDisplayName` directly with `Path_Get(hpth)` which may include the prefix.
### Sketch
Inside `EditOpenContainingFolderFromSelection` in `src\Notepad3.c`, before `SHParseDisplayName`:
```c
LPCWSTR pth = Path_Get(hpth);
if (StrCmpNW(pth, L"\\\\?\\", 4) == 0) {
// Skip the prefix for shell-API use. If \\?\UNC\..., strip differently.
if (StrCmpNW(pth + 4, L"UNC\\", 4) == 0) {
// \\?\UNC\server\share → \\server\share
WCHAR shellPath[MAX_PATH_EXPLICIT];
StringCchPrintf(shellPath, COUNTOF(shellPath), L"\\\\%s", pth + 8);
SHParseDisplayName(shellPath, ...);
} else {
SHParseDisplayName(pth + 4, ...);
}
}
```
### Verification
- `\\?\C:\Windows` → opens `C:\Windows` in Explorer.
- `\\?\UNC\server\share\file.txt` → opens `\\server\share\` with `file.txt` selected.
## Item 5 — `#fragment` parsing for `file://` URLs
**Goal**: a `file:///D:/docs/readme.md#section-2` URL clicked in Notepad3 should at minimum open the file (currently works) and ideally jump to the line with `#section-2` as a heading anchor.
### Why deferred
Markdown anchor resolution is out of scope for a text editor — the heading-anchor mapping is a Markdown-specific convention. The minimum useful behavior is to strip `#...` before resolving the path. Currently `PathCreateFromUrlW` may or may not strip it depending on Windows version.
### Sketch
In `HandleHotSpotURLClicked` at `src\Notepad3.c:8824`, after `PathCreateFromUrlW`:
```c
LPWSTR const hash = StrChr(szUnEscW, L'#');
if (hash) {
*hash = L'\0'; // discard fragment
}
```
A future Markdown-aware extension could parse `#anchor-name`, scan the buffer for `## Anchor Name` (case-insensitive, dashes→spaces), and `SCI_GOTOLINE` there. Probably not worth the complexity.
### Verification
Click `file:///D:/test/foo.md#whatever` — opens `foo.md`. Don't error or attempt to interpret `#whatever`.
## Item 6 — Localize the new menu strings (translator task, not Claude's)
The 25 sibling locales currently have **English placeholder** strings for the two new menu items. Translators need to update:
- `language\np3_*\menu_*.rc` — replace `"Open &Containing Folder of Selection\tCtrl+Shift+,"` and `"Open &File from Selection"` (both in Edit > Miscellaneous AND in `IDR_MUI_POPUPMENU`).
This is normal translator workflow — not blocked, just pending.
### What Claude can do
Nothing without authoritative translations. If asked to "translate", refuse and ask the user to source translations from the locale maintainers listed in `language\np3_*\strings_*.rc` (`IDS_MUI_TRANSL_AUTHOR`).
## Item 7 — Tinyexpr behavior in `SplitFilePathLineColNum` `:N` fallback
`SplitFilePathLineColNum` falls back to `SplitFilePathLineNum` (which uses `te_interp`) for the single-colon case `foo.c:42`. This means `foo.c:42+1` would parse as line 43 — a side effect of using tinyexpr. Two existing callers depend on this:
- `src\Notepad3.c:8666``SplitFilePathLineNum(wchUrl, NULL)` — only cuts the suffix, discards the number.
- `src\Notepad3.c:8879``SplitFilePathLineNum(szTextW, &lineNum)` — uses the parsed number.
If we ever want to drop the tinyexpr quirk: replace the wrapper with a plain `_wtoi` parse. Verify the two existing callers don't pass arithmetic.
## Touch-stones for any future session
- **CLAUDE.md** in repo root has all the build/encoding/localization invariants. Read it before touching `.rc` files.
- **`.venv\Scripts\python.exe`** is required for bulk locale edits. Do NOT use sed/perl.
- **`.rc` files** are UTF-8 *without* BOM, CRLF. Use `Build\rc_to_utf8.cmd` if a BOM sneaks in.
- **Locale es_la** has an empty directory — script-based bulk edits should skip it gracefully.
- **Reference impl**: Notepad4 at `D:\DEV\GitHub\notepad4\` — inspect `src\Edit.cpp` (`EditOpenSelection`, `EditGetStringAroundCaret`) and `src\Helpers.cpp` (`OpenContainingFolder`).
- **Build**: `Build\Build_x64.cmd Release` for quick verification. The Build.ps1 wrapper has quoting quirks under some PowerShell versions — invoke MSBuild directly if it fails: `& "C:\Program Files\Microsoft Visual Studio\18\Community\MSBuild\Current\Bin\MSBuild.exe" "D:\DEV\GitHub\Notepad3\Notepad3.sln" /m /p:Configuration=Release /p:Platform=x64 /v:minimal`.
## Out of scope for these follow-ups
- IDS_MUI_* / Notepad3DLL string resources — none of the deferred items add user-facing strings beyond menu labels (which are inline in `.rc`).
- ARM64-specific concerns — none of these touch rendering or CET paths.
- grepWin integration — orthogonal.

View File

@ -57,6 +57,8 @@ void EditChar2Hex(HWND hwnd);
void EditHex2Char(HWND hwnd);
void EditFindMatchingBrace();
void EditSelectToMatchingBrace();
void EditOpenContainingFolderFromSelection(void);
void EditOpenFileFromSelection(HWND hwnd);
void EditModifyNumber(HWND hwnd, bool bIncrease);
void EditInsertDateTimeStrg(bool bShortFmt, bool bTimestampFmt);
void EditUpdateTimestamps();

View File

@ -1164,6 +1164,329 @@ bool SplitFilePathLineNum(LPWSTR lpszPath, int* lineNum)
}
//=============================================================================
//
// _IsAllDigitsW() - non-empty wide string consisting solely of ASCII digits
//
static inline bool _IsAllDigitsW(LPCWSTR s)
{
if (!s || *s == L'\0') {
return false;
}
for (; *s; ++s) {
if (*s < L'0' || *s > L'9') {
return false;
}
}
return true;
}
//=============================================================================
//
// _StripCommonQuoting() - in-place strip of whitespace + quote-like chars
// that wrap a path/URL token in source/log/doc text.
//
static inline void _StripCommonQuoting(HSTRINGW hstr)
{
StrgTrim(hstr, L' ');
StrgTrim(hstr, L'\t');
StrgTrim(hstr, L'"');
StrgTrim(hstr, L'\'');
StrgTrim(hstr, L'`');
StrgTrim(hstr, L'<');
StrgTrim(hstr, L'>');
}
//=============================================================================
//
// SplitFilePathLineColNum()
//
// Strips an optional trailing line/column suffix from lpszPath in place.
// Patterns recognised (first match wins):
// foo.c(42) -> line 42
// foo.c,42 -> line 42
// foo.c:42:7 -> line 42, column 7
// foo.c:<expr> -> falls through to SplitFilePathLineNum (te_interp)
//
// Drive-letter colons ("C:\...") are never treated as line separators.
// Returns true if a suffix was stripped.
//
bool SplitFilePathLineColNum(LPWSTR lpszPath, int* lineNum, int* colNum)
{
if (lineNum) {
*lineNum = -1;
}
if (colNum) {
*colNum = -1;
}
if (StrIsEmpty(lpszPath)) {
return false;
}
size_t len = StrlenW(lpszPath);
while (len > 0 && (lpszPath[len - 1] == L' ' || lpszPath[len - 1] == L'\t')) {
lpszPath[--len] = L'\0';
}
if (len == 0) {
return false;
}
// Try trailing "(N)"
if (lpszPath[len - 1] == L')') {
size_t j = len - 1; // points at ')'
while (j > 0 && lpszPath[j - 1] >= L'0' && lpszPath[j - 1] <= L'9') {
--j;
}
if (j < (len - 1) && j > 0 && lpszPath[j - 1] == L'(') {
int const ln = _wtoi(&lpszPath[j]);
if (ln > 0) {
lpszPath[j - 1] = L'\0';
if (lineNum) {
*lineNum = ln;
}
return true;
}
}
}
// Try trailing ",N"
{
size_t i = len;
while (i > 0 && lpszPath[i - 1] >= L'0' && lpszPath[i - 1] <= L'9') {
--i;
}
if (i < len && i > 0 && lpszPath[i - 1] == L',') {
int const ln = _wtoi(&lpszPath[i]);
if (ln > 0) {
lpszPath[i - 1] = L'\0';
if (lineNum) {
*lineNum = ln;
}
return true;
}
}
}
// Try trailing ":N:M" (line + column). Reject drive-letter colon at pos 1.
LPWSTR lastColon = StrRChr(lpszPath, NULL, L':');
if (lastColon && lastColon != (lpszPath + 1) && _IsAllDigitsW(lastColon + 1)) {
int const second = _wtoi(lastColon + 1);
wchar_t const saved = *lastColon;
*lastColon = L'\0';
LPWSTR prevColon = StrRChr(lpszPath, NULL, L':');
if (prevColon && prevColon != (lpszPath + 1) && _IsAllDigitsW(prevColon + 1)) {
int const first = _wtoi(prevColon + 1);
if (first > 0 && second > 0) {
*prevColon = L'\0';
if (lineNum) {
*lineNum = first;
}
if (colNum) {
*colNum = second;
}
return true;
}
}
*lastColon = saved;
}
// Single-colon fallback (preserves te_interp expression support)
return SplitFilePathLineNum(lpszPath, lineNum);
}
//=============================================================================
//
// _IsTokenBoundary() - true for chars that delimit a path/URL token
// when no selection is present.
//
static inline bool _IsTokenBoundary(char c)
{
switch (c) {
case ' ': case '\t': case '\r': case '\n':
case '\'': case '`': case '"':
case '<': case '>': case '|': case '*':
case ',': case ';':
return true;
default:
return false;
}
}
//=============================================================================
//
// ExtractSelectionOrTokenAtCaret()
//
// Returns a freshly-allocated HSTRINGW (caller must StrgDestroy()) holding
// the current selection, or - if the selection is empty - the span around
// the caret bounded by [\s'`"<>|*,;]. Newline-truncates selections.
// Strips surrounding whitespace and quote-like characters.
//
HSTRINGW ExtractSelectionOrTokenAtCaret(void)
{
HSTRINGW hstr = StrgCreate(NULL);
DocPos byteStart = 0;
DocPos byteEnd = 0;
if (!SciCall_IsSelectionEmpty()) {
byteStart = SciCall_GetSelectionStart();
byteEnd = SciCall_GetSelectionEnd();
// truncate selection at first \r, \n, \t
for (DocPos p = byteStart; p < byteEnd; ++p) {
char const c = SciCall_GetCharAt(p);
if (c == '\r' || c == '\n' || c == '\t') {
byteEnd = p;
break;
}
}
}
else {
DocPos const pos = SciCall_GetCurrentPos();
DocLn const ln = SciCall_LineFromPosition(pos);
DocPos const lineStart = SciCall_PositionFromLine(ln);
DocPos const lineEnd = SciCall_GetLineEndPosition(ln);
byteStart = pos;
while (byteStart > lineStart && !_IsTokenBoundary(SciCall_GetCharAt(byteStart - 1))) {
--byteStart;
}
byteEnd = pos;
while (byteEnd < lineEnd && !_IsTokenBoundary(SciCall_GetCharAt(byteEnd))) {
++byteEnd;
}
}
if (byteEnd > byteStart) {
DocPos const length = byteEnd - byteStart;
const char* const pszRange = SciCall_GetRangePointer(byteStart, length);
if (pszRange) {
int const wlen = MultiByteToWideChar(Encoding_SciCP, 0, pszRange, (int)length, NULL, 0);
if (wlen > 0) {
LPWSTR const buf = StrgWriteAccessBuf(hstr, (size_t)wlen + 1);
int const written = MultiByteToWideChar(Encoding_SciCP, 0, pszRange, (int)length, buf, wlen);
buf[written] = L'\0';
StrgSanitize(hstr);
}
}
}
if (StrgIsNotEmpty(hstr)) {
_StripCommonQuoting(hstr);
}
return hstr;
}
//=============================================================================
//
// Path_CanonicalizeWithDocAnchor()
//
// In-place canonicalisation using the document-anchor priority:
// 1) directory of Paths.CurrentFile (when non-empty)
// 2) Paths.WorkingDirectory (fallback)
// never Paths.ModuleDirectory.
//
// Safe to call for both relative and absolute paths — Path_CanonicalizeEx
// only joins the anchor when the path IS relative.
//
void Path_CanonicalizeWithDocAnchor(HPATHL hpth)
{
HPATHL hAnchor = Path_Allocate(NULL);
if (Path_IsNotEmpty(Paths.CurrentFile)) {
Path_Reset(hAnchor, Path_Get(Paths.CurrentFile));
Path_RemoveFileSpec(hAnchor);
}
if (Path_IsEmpty(hAnchor) && Path_IsNotEmpty(Paths.WorkingDirectory)) {
Path_Reset(hAnchor, Path_Get(Paths.WorkingDirectory));
}
Path_CanonicalizeEx(hpth, hAnchor);
Path_Release(hAnchor);
}
//=============================================================================
//
// ResolveSelectionToPath()
//
// Best-effort resolution of a selection token to an absolute filesystem path.
//
// Steps:
// - Strip a leading file:// / file:/// prefix via PathCreateFromUrlW.
// - Expand %VAR% environment references.
// - If relative: canonicalise against (1) the directory of Paths.CurrentFile
// when non-empty, otherwise (2) Paths.WorkingDirectory.
// NEVER against Paths.ModuleDirectory.
// - Probe filesystem; set *isDir true for an existing directory.
//
// Returns true iff the resolved path exists. hpthOut is always populated
// with the best-effort resolution (caller may inspect on false).
//
bool ResolveSelectionToPath(LPCWSTR token, HPATHL hpthOut, bool* isDir)
{
if (isDir) {
*isDir = false;
}
if (!hpthOut) {
return false;
}
Path_Empty(hpthOut, true);
if (StrIsEmpty(token)) {
return false;
}
// Defensive: callers may pass un-trimmed input. '<' '>' are shell-quote /
// mail-style URL wrappers, never legitimate at a path-token boundary —
// safe to strip even though they are valid filename chars mid-name.
HSTRINGW htmp = StrgCreate(token);
_StripCommonQuoting(htmp);
if (StrgIsEmpty(htmp)) {
StrgDestroy(htmp);
return false;
}
// file:// / file:/// -> Windows path. Try Shell's PathCreateFromUrlW first;
// on failure (malformed URL), fall back to a manual prefix strip so the
// canonicalization step below still has a usable best-effort path.
LPCWSTR const raw = StrgGet(htmp);
if (StrCmpNIW(raw, L"file://", 7) == 0) {
WCHAR szPath[INTERNET_MAX_URL_LENGTH + 1] = { L'\0' };
DWORD cch = COUNTOF(szPath);
if (SUCCEEDED(PathCreateFromUrlW(raw, szPath, &cch, 0))) {
StrgReset(htmp, szPath);
}
else {
size_t const skip = (StrCmpNIW(raw, L"file:///", 8) == 0) ? 8 : 7;
HSTRINGW hStripped = StrgCreate(raw + skip);
StrgSwap(htmp, hStripped);
StrgDestroy(hStripped);
}
}
// Path_CanonicalizeEx already runs ExpandEnvironmentStrgs(hstr, true) and
// strips quotes — no need to expand env vars manually here.
Path_Reset(hpthOut, StrgGet(htmp));
StrgDestroy(htmp);
Path_CanonicalizeWithDocAnchor(hpthOut);
if (Path_IsExistingFile(hpthOut)) {
return true;
}
if (Path_IsExistingDirectory(hpthOut)) {
if (isDir) {
*isDir = true;
}
return true;
}
return false;
}
//=============================================================================
//
// FormatNumberStr()

View File

@ -486,6 +486,11 @@ bool ReadFileXL(HANDLE hFile, char* const lpBuffer, const size_t nNumberOfBytesT
bool WriteFileXL(HANDLE hFile, const char* const lpBuffer, const size_t nNumberOfBytesToWrite, size_t* const lpNumberOfBytesWritten);
bool SplitFilePathLineNum(LPWSTR lpszPath, int *lineNum);
bool SplitFilePathLineColNum(LPWSTR lpszPath, int *lineNum, int *colNum);
HSTRINGW ExtractSelectionOrTokenAtCaret(void);
bool ResolveSelectionToPath(LPCWSTR token, HPATHL hpthOut, bool *isDir);
void Path_CanonicalizeWithDocAnchor(HPATHL hpth);
bool StrLTrimI(LPWSTR pszSource,LPCWSTR pszTrimChars);
bool StrRTrimI(LPWSTR pszSource,LPCWSTR pszTrimChars);

View File

@ -6017,6 +6017,132 @@ static bool _HandleEditBasicCommands(HWND hwnd, UINT umsg, WPARAM wParam, LPARAM
}
//=============================================================================
//
// _ResolveSelectionForOpen()
//
// Shared preamble for the EditOpen*FromSelection commands:
// extract token at selection/caret -> strip line/col suffix -> resolve.
// Returns a freshly-allocated HPATHL on success (caller must Path_Release),
// or NULL when no token or no resolvable path was found.
// *lineNum / *isDir are output-only; either may be NULL.
//
static HPATHL _ResolveSelectionForOpen(int* lineNum, bool* isDir)
{
if (lineNum) {
*lineNum = -1;
}
HSTRINGW hToken = ExtractSelectionOrTokenAtCaret();
if (StrgIsEmpty(hToken)) {
StrgDestroy(hToken);
return NULL;
}
LPWSTR const tokBuf = StrgWriteAccessBuf(hToken, 0);
SplitFilePathLineColNum(tokBuf, lineNum, NULL);
StrgSanitize(hToken);
HPATHL hpth = Path_Allocate(NULL);
bool const ok = ResolveSelectionToPath(StrgGet(hToken), hpth, isDir);
StrgDestroy(hToken);
if (!ok) {
Path_Release(hpth);
return NULL;
}
return hpth;
}
//=============================================================================
//
// EditOpenContainingFolderFromSelection()
//
// Resolves the current selection (or token at the caret) to a filesystem
// path and opens Explorer with that file/folder selected.
//
// Implemented in Notepad3.c (not Edit.c) because <shlobj.h> defines
// SORT_ASCENDING / SORT_DESCENDING that collide with Edit.c's SortOrderMask.
//
void EditOpenContainingFolderFromSelection(void)
{
HPATHL hpth = _ResolveSelectionForOpen(NULL, NULL);
if (!hpth) {
MessageBeep(MB_ICONHAND);
return;
}
PIDLIST_ABSOLUTE pidl = NULL;
SHParseDisplayName(Path_Get(hpth), NULL, &pidl, SFGAO_BROWSABLE | SFGAO_FILESYSTEM, NULL);
if (pidl) {
SHOpenFolderAndSelectItems(pidl, 0, NULL, 0);
ILFree(pidl);
}
Path_Release(hpth);
}
//=============================================================================
//
// EditOpenFileFromSelection()
//
// Resolves the selection (or token at the caret) to a file path, then loads
// it into Notepad3 (mirrors the OPEN_IN_NOTEPAD3 branch of the hyperlink
// handler). For a directory, opens the file-open dialog rooted there.
//
void EditOpenFileFromSelection(HWND hwnd)
{
UNREFERENCED_PARAMETER(hwnd);
int lineNum = -1;
bool isDir = false;
HPATHL hpth = _ResolveSelectionForOpen(&lineNum, &isDir);
if (!hpth) {
MessageBeep(MB_ICONHAND);
return;
}
bool const bReuseWindow = Flags.bReuseWindow;
FileLoadFlags fLoadFlags = FLF_None;
fLoadFlags |= Settings.SkipUnicodeDetection ? FLF_SkipUnicodeDetect : 0;
fLoadFlags |= Settings.SkipANSICodePageDetection ? FLF_SkipANSICPDetection : 0;
bool success = false;
if (!isDir) {
if (bReuseWindow) {
success = FileLoad(hpth, fLoadFlags, 0, 0);
if (success && lineNum > 0) {
int const ln = clampi(lineNum - 1, 0, INT_MAX);
SciCall_PostMsg(SCI_GOTOLINE, (WPARAM)ln, 0);
}
}
else {
WCHAR wchParams[64];
StringCchPrintf(wchParams, COUNTOF(wchParams), L"%s /g %i",
Flags.bSingleFileInstance ? L"/ns" : L"/n", clampi(lineNum, 0, INT_MAX));
success = LaunchNewInstance(Globals.hwndMain, wchParams, Path_Get(hpth));
}
}
else {
if (bReuseWindow) {
if (OpenFileDlg(Globals.hwndMain, hpth, hpth)) {
success = FileLoad(hpth, fLoadFlags, 0, 0);
}
}
else {
WCHAR wchParams[64];
StringCchPrintf(wchParams, COUNTOF(wchParams), L"%s",
Flags.bSingleFileInstance ? L"/ns" : L"/n");
success = LaunchNewInstance(Globals.hwndMain, wchParams, Path_Get(hpth));
}
}
if (!success) {
MessageBeep(MB_ICONHAND);
}
Path_Release(hpth);
}
//=============================================================================
//
// _HandleEditLineManipulation() - Handler for MsgCommand()
@ -6321,6 +6447,15 @@ static bool _HandleEditLineManipulation(HWND hwnd, UINT umsg, WPARAM wParam, LPA
break;
case IDM_EDIT_OPEN_CONTAINING_FOLDER_SEL:
EditOpenContainingFolderFromSelection();
break;
case IDM_EDIT_OPEN_FILE_FROM_SEL:
EditOpenFileFromSelection(hwnd);
break;
default:
return false;
@ -8888,8 +9023,11 @@ bool HandleHotSpotURLClicked(const DocPos position, const HYPERLINK_OPS operatio
StrTrim(szUnEscW, L"/");
HPATHL hfile_pth = Path_Allocate(szUnEscW);
Path_CanonicalizeEx(hfile_pth, Paths.ModuleDirectory);
//@@@???Path_CanonicalizeEx(hfile_pth, Paths.WorkingDirectory);
// Anchor relative file:// URLs to the directory of the current
// document, falling back to the working directory. Never to
// Paths.ModuleDirectory — that resolves against Notepad3's
// install dir, which is rarely what the author intended.
Path_CanonicalizeWithDocAnchor(hfile_pth);
bool success = false;
FileLoadFlags fLoadFlags = FLF_None;

View File

@ -341,7 +341,7 @@
- BUG: [#4952](https://github.com/rizonesoft/Notepad3/issues/4952) - Template vs Action naming inconsistency
- [ ] **(Q2) Open Path or Link** - Open file path or URL under cursor
- Issue: [#3926](https://github.com/rizonesoft/Notepad3/issues/3926) - Support relative file:// paths
- [ ] **(Q1) Open Containing Folder** - Open the folder containing the current file in Explorer
- [x] **(Q1) Open Containing Folder** - Open the folder containing the current file in Explorer - ✅ IMPLEMENTED
- **Reference**: [Notepad4](https://github.com/zufuliu/notepad4) implements via `CMD_OPEN_CONTAINING_FOLDER` and `EditOpenSelection(OpenSelectionType_ContainingFolder)`
### Windows Integration