diff --git a/language/common_res.h b/language/common_res.h index c358b4285..a97b14cdb 100644 --- a/language/common_res.h +++ b/language/common_res.h @@ -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 diff --git a/language/np3_af_za/menu_af_za.rc b/language/np3_af_za/menu_af_za.rc index 32e86d06d..b4036d17f 100644 --- a/language/np3_af_za/menu_af_za.rc +++ b/language/np3_af_za/menu_af_za.rc @@ -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 "+" diff --git a/language/np3_be_by/menu_be_by.rc b/language/np3_be_by/menu_be_by.rc index 74d075d54..801b83d2f 100644 --- a/language/np3_be_by/menu_be_by.rc +++ b/language/np3_be_by/menu_be_by.rc @@ -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 "+" diff --git a/language/np3_de_de/menu_de_de.rc b/language/np3_de_de/menu_de_de.rc index f449537d2..98475b394 100644 --- a/language/np3_de_de/menu_de_de.rc +++ b/language/np3_de_de/menu_de_de.rc @@ -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 "+" diff --git a/language/np3_el_gr/menu_el_gr.rc b/language/np3_el_gr/menu_el_gr.rc index 03904c63d..a1bfda5de 100644 --- a/language/np3_el_gr/menu_el_gr.rc +++ b/language/np3_el_gr/menu_el_gr.rc @@ -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 "+" diff --git a/language/np3_en_gb/menu_en_gb.rc b/language/np3_en_gb/menu_en_gb.rc index 0ad2176e0..661fa33e6 100644 --- a/language/np3_en_gb/menu_en_gb.rc +++ b/language/np3_en_gb/menu_en_gb.rc @@ -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 "+" diff --git a/language/np3_en_us/menu_en_us.rc b/language/np3_en_us/menu_en_us.rc index b04a293c2..8e6499725 100644 --- a/language/np3_en_us/menu_en_us.rc +++ b/language/np3_en_us/menu_en_us.rc @@ -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 "+" diff --git a/language/np3_es_es/menu_es_es.rc b/language/np3_es_es/menu_es_es.rc index b527d7502..9d6712706 100644 --- a/language/np3_es_es/menu_es_es.rc +++ b/language/np3_es_es/menu_es_es.rc @@ -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 "+" diff --git a/language/np3_fi_fi/menu_fi_fi.rc b/language/np3_fi_fi/menu_fi_fi.rc index 92dac2d11..abbc6f4d2 100644 --- a/language/np3_fi_fi/menu_fi_fi.rc +++ b/language/np3_fi_fi/menu_fi_fi.rc @@ -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 "+" diff --git a/language/np3_fr_fr/menu_fr_fr.rc b/language/np3_fr_fr/menu_fr_fr.rc index 726196751..fc0af000e 100644 --- a/language/np3_fr_fr/menu_fr_fr.rc +++ b/language/np3_fr_fr/menu_fr_fr.rc @@ -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 "+" diff --git a/language/np3_hi_in/menu_hi_in.rc b/language/np3_hi_in/menu_hi_in.rc index 3b9a80559..b9dd80ae9 100644 --- a/language/np3_hi_in/menu_hi_in.rc +++ b/language/np3_hi_in/menu_hi_in.rc @@ -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 "+" diff --git a/language/np3_hu_hu/menu_hu_hu.rc b/language/np3_hu_hu/menu_hu_hu.rc index 09d838140..b9c45e859 100644 --- a/language/np3_hu_hu/menu_hu_hu.rc +++ b/language/np3_hu_hu/menu_hu_hu.rc @@ -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 "+" diff --git a/language/np3_id_id/menu_id_id.rc b/language/np3_id_id/menu_id_id.rc index 772cd3466..d266eac8b 100644 --- a/language/np3_id_id/menu_id_id.rc +++ b/language/np3_id_id/menu_id_id.rc @@ -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 "+" diff --git a/language/np3_it_it/menu_it_it.rc b/language/np3_it_it/menu_it_it.rc index 8645617d3..c3a8498d0 100644 --- a/language/np3_it_it/menu_it_it.rc +++ b/language/np3_it_it/menu_it_it.rc @@ -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 "+" diff --git a/language/np3_ja_jp/menu_ja_jp.rc b/language/np3_ja_jp/menu_ja_jp.rc index 14490e599..c62b671ab 100644 --- a/language/np3_ja_jp/menu_ja_jp.rc +++ b/language/np3_ja_jp/menu_ja_jp.rc @@ -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 "+" diff --git a/language/np3_ko_kr/menu_ko_kr.rc b/language/np3_ko_kr/menu_ko_kr.rc index f4d45b717..b95650baa 100644 --- a/language/np3_ko_kr/menu_ko_kr.rc +++ b/language/np3_ko_kr/menu_ko_kr.rc @@ -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 "+" diff --git a/language/np3_nl_nl/menu_nl_nl.rc b/language/np3_nl_nl/menu_nl_nl.rc index 49b5564ca..854107562 100644 --- a/language/np3_nl_nl/menu_nl_nl.rc +++ b/language/np3_nl_nl/menu_nl_nl.rc @@ -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 "+" diff --git a/language/np3_pl_pl/menu_pl_pl.rc b/language/np3_pl_pl/menu_pl_pl.rc index d740970d8..f98848f29 100644 --- a/language/np3_pl_pl/menu_pl_pl.rc +++ b/language/np3_pl_pl/menu_pl_pl.rc @@ -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 "+" diff --git a/language/np3_pt_br/menu_pt_br.rc b/language/np3_pt_br/menu_pt_br.rc index def8df49c..8c2caa6e4 100644 --- a/language/np3_pt_br/menu_pt_br.rc +++ b/language/np3_pt_br/menu_pt_br.rc @@ -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 "+" diff --git a/language/np3_pt_pt/menu_pt_pt.rc b/language/np3_pt_pt/menu_pt_pt.rc index 92efddda1..fee067e29 100644 --- a/language/np3_pt_pt/menu_pt_pt.rc +++ b/language/np3_pt_pt/menu_pt_pt.rc @@ -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 "+" diff --git a/language/np3_ru_ru/menu_ru_ru.rc b/language/np3_ru_ru/menu_ru_ru.rc index e0e2bb9f3..079efdb45 100644 --- a/language/np3_ru_ru/menu_ru_ru.rc +++ b/language/np3_ru_ru/menu_ru_ru.rc @@ -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 "+" diff --git a/language/np3_sk_sk/menu_sk_sk.rc b/language/np3_sk_sk/menu_sk_sk.rc index 73d9cefa7..1d6c589a1 100644 --- a/language/np3_sk_sk/menu_sk_sk.rc +++ b/language/np3_sk_sk/menu_sk_sk.rc @@ -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 "+" diff --git a/language/np3_sv_se/menu_sv_se.rc b/language/np3_sv_se/menu_sv_se.rc index 78c3bfb5c..b898c29a7 100644 --- a/language/np3_sv_se/menu_sv_se.rc +++ b/language/np3_sv_se/menu_sv_se.rc @@ -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 "+" diff --git a/language/np3_tr_tr/menu_tr_tr.rc b/language/np3_tr_tr/menu_tr_tr.rc index b073f4220..354717bae 100644 --- a/language/np3_tr_tr/menu_tr_tr.rc +++ b/language/np3_tr_tr/menu_tr_tr.rc @@ -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 "+" diff --git a/language/np3_vi_vn/menu_vi_vn.rc b/language/np3_vi_vn/menu_vi_vn.rc index f715f4f25..58c5a4235 100644 --- a/language/np3_vi_vn/menu_vi_vn.rc +++ b/language/np3_vi_vn/menu_vi_vn.rc @@ -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 "+" diff --git a/language/np3_zh_cn/menu_zh_cn.rc b/language/np3_zh_cn/menu_zh_cn.rc index acc1c7ce7..229a36768 100644 --- a/language/np3_zh_cn/menu_zh_cn.rc +++ b/language/np3_zh_cn/menu_zh_cn.rc @@ -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 "+" diff --git a/language/np3_zh_tw/menu_zh_tw.rc b/language/np3_zh_tw/menu_zh_tw.rc index bcac21d00..38f1775b3 100644 --- a/language/np3_zh_tw/menu_zh_tw.rc +++ b/language/np3_zh_tw/menu_zh_tw.rc @@ -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 "+" diff --git a/plans/explore_file_refs.md b/plans/explore_file_refs.md new file mode 100644 index 000000000..820466a7d --- /dev/null +++ b/plans/explore_file_refs.md @@ -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 `` 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. diff --git a/src/Edit.h b/src/Edit.h index ea06130fa..fe4d4dee3 100644 --- a/src/Edit.h +++ b/src/Edit.h @@ -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(); diff --git a/src/Helpers.c b/src/Helpers.c index f416c82f8..f0ddc377b 100644 --- a/src/Helpers.c +++ b/src/Helpers.c @@ -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: -> 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() diff --git a/src/Helpers.h b/src/Helpers.h index c3df5b60a..0246c944a 100644 --- a/src/Helpers.h +++ b/src/Helpers.h @@ -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); diff --git a/src/Notepad3.c b/src/Notepad3.c index 89a0b8585..a00ff6a32 100644 --- a/src/Notepad3.c +++ b/src/Notepad3.c @@ -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 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; diff --git a/todo/TODO.md b/todo/TODO.md index 34d21bbee..83c8ee2f6 100644 --- a/todo/TODO.md +++ b/todo/TODO.md @@ -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