@@ -322,7 +322,85 @@ void ResultDock::formatHitsForFile(const std::wstring& wPath,
322
322
formatHitsLines (sciSend, hits, out, utf8Pos);
323
323
}
324
324
325
+ void ResultDock::formatHitsLines (const SciSendFn& sciSend,
326
+ std::vector<Hit>& hits,
327
+ std::wstring& out,
328
+ size_t & utf8Pos) const
329
+ {
330
+ constexpr wchar_t INDENT_W[] = L" " ;
331
+ constexpr size_t INDENT_U8 = 12 ;
332
+
333
+ const UINT docCp = static_cast <UINT>(sciSend (SCI_GETCODEPAGE, 0 , 0 ));
334
+
335
+ int prevLine = -1 ;
336
+ Hit* firstHitOnLine = nullptr ;
337
+
338
+ for (Hit& h : hits)
339
+ {
340
+ int lineZero = (int )sciSend (SCI_LINEFROMPOSITION, h.pos , 0 );
341
+ int lineOne = lineZero + 1 ;
342
+
343
+ /* --- read raw bytes ------------------------------------ */
344
+ int rawLen = (int )sciSend (SCI_LINELENGTH, lineZero, 0 );
345
+ std::string raw (rawLen, ' \0 ' );
346
+ sciSend (SCI_GETLINE, lineZero, (LPARAM)raw.data ());
347
+ raw.resize (strnlen (raw.c_str (), rawLen));
348
+ while (!raw.empty () && (raw.back () == ' \r ' || raw.back () == ' \n ' ))
349
+ raw.pop_back ();
350
+
351
+ /* --- trim leading blanks ------------------------------- */
352
+ size_t lead = raw.find_first_not_of (" \t " );
353
+ std::string_view sliceBytes =
354
+ (lead == std::string::npos) ? std::string_view{}
355
+ : std::string_view (raw).substr (lead);
356
+
357
+ /* --- FULL slice as UTF‑8 (★) --------------------------- */
358
+ const std::string sliceU8 = Encoding::bytesToUtf8 (sliceBytes, docCp);
359
+ const std::wstring sliceW = Encoding::utf8ToWString (sliceU8);
360
+
361
+ /* --- prefix -------------------------------------------- */
362
+ std::wstring prefixW = std::wstring (INDENT_W)
363
+ + L" Line " + std::to_wstring (lineOne) + L" : " ;
364
+ size_t prefixU8Len = Encoding::wstringToUtf8 (prefixW).size ();
365
+
366
+ /* --- byte offset of hit inside slice ------------------- */
367
+ Sci_Position absTrimmed = sciSend (SCI_POSITIONFROMLINE, lineZero, 0 ) + (Sci_Position)lead;
368
+ size_t relBytes = (size_t )(h.pos - absTrimmed);
325
369
370
+ /* --- locate hit in UTF‑8 text (★) --------------------- */
371
+ size_t hitStartInSlice = Encoding::bytesToUtf8 (
372
+ sliceBytes.substr (0 , relBytes), docCp).size ();
373
+ size_t hitLenU8 = Encoding::bytesToUtf8 (
374
+ sliceBytes.substr (relBytes, h.length ), docCp).size ();
375
+
376
+ /* --- first hit on this visual line? -------------------- */
377
+ if (lineZero != prevLine)
378
+ {
379
+ out += prefixW + sliceW + L" \r\n " ;
380
+
381
+ h.displayLineStart = (int )utf8Pos;
382
+ h.numberStart = (int )(INDENT_U8 + 5 );
383
+ h.numberLen = (int )std::to_string (lineOne).size ();
384
+ h.matchStarts = { (int )(prefixU8Len + hitStartInSlice) };
385
+ h.matchLens = { (int )hitLenU8 };
386
+
387
+ utf8Pos += prefixU8Len + sliceU8.size () + 2 ;
388
+ firstHitOnLine = &h;
389
+ prevLine = lineZero;
390
+ }
391
+ else /* additional hit on same line */
392
+ {
393
+ firstHitOnLine->matchStarts .push_back (
394
+ (int )(prefixU8Len + hitStartInSlice));
395
+ firstHitOnLine->matchLens .push_back ((int )hitLenU8);
396
+ h.displayLineStart = -1 ; // dummy
397
+ }
398
+ }
399
+
400
+ hits.erase (std::remove_if (hits.begin (), hits.end (),
401
+ [](const Hit& h) { return h.displayLineStart < 0 ; }),
402
+ hits.end ());
403
+ }
326
404
327
405
// --- Private Methods ---
328
406
@@ -710,7 +788,6 @@ void ResultDock::applyStyling() const
710
788
h.matchLens [i]);
711
789
}
712
790
713
-
714
791
LRESULT CALLBACK ResultDock::sciSubclassProc (HWND hwnd, UINT msg, WPARAM wp, LPARAM lp)
715
792
{
716
793
extern NppData nppData;
@@ -743,10 +820,27 @@ LRESULT CALLBACK ResultDock::sciSubclassProc(HWND hwnd, UINT msg, WPARAM wp, LPA
743
820
LRESULT firstVisible = ::SendMessage (hwnd, SCI_GETFIRSTVISIBLELINE, 0 , 0 );
744
821
745
822
// 2) Which display‐line was clicked?
746
- int x = (short )LOWORD (lp), y = (short )HIWORD (lp);
823
+ int x = LOWORD (lp);
824
+ int y = HIWORD (lp);
747
825
Sci_Position pos = ::SendMessage (hwnd, SCI_POSITIONFROMPOINT, x, y);
826
+ if (pos < 0 ) // guard for empty area
827
+ return 0 ;
748
828
int dispLine = (int )::SendMessage (hwnd, SCI_LINEFROMPOSITION, pos, 0 );
749
829
830
+ // --- Toggle fold if the clicked line is a header ----------
831
+ int level = (int )::SendMessage (hwnd, SCI_GETFOLDLEVEL, dispLine, 0 );
832
+ if (level & SC_FOLDLEVELHEADERFLAG)
833
+ {
834
+ ::SendMessage (hwnd, SCI_TOGGLEFOLD, dispLine, 0 );
835
+ // --- remove double‑click word selection & keep scroll ----------
836
+ Sci_Position linePos = (Sci_Position)::SendMessage (
837
+ hwnd, SCI_POSITIONFROMLINE, dispLine, 0 );
838
+ ::SendMessage (hwnd, SCI_SETEMPTYSELECTION, linePos, 0 );
839
+ ::SendMessage (hwnd, SCI_SETFIRSTVISIBLELINE, firstVisible, 0 );
840
+
841
+ return 0 ;
842
+ }
843
+
750
844
// 3) Read the raw text of that line
751
845
int lineLen = (int )::SendMessage (hwnd, SCI_LINELENGTH, dispLine, 0 );
752
846
std::string raw (lineLen, ' \0 ' );
@@ -841,85 +935,6 @@ LRESULT CALLBACK ResultDock::sciSubclassProc(HWND hwnd, UINT msg, WPARAM wp, LPA
841
935
: ::DefWindowProc (hwnd, msg, wp, lp);
842
936
}
843
937
844
- void ResultDock::formatHitsLines (const SciSendFn& sciSend,
845
- std::vector<Hit>& hits,
846
- std::wstring& out,
847
- size_t & utf8Pos) const
848
- {
849
- constexpr wchar_t INDENT_W[] = L" " ;
850
- constexpr size_t INDENT_U8 = 12 ;
851
-
852
- const UINT docCp = static_cast <UINT>(sciSend (SCI_GETCODEPAGE, 0 , 0 ));
853
-
854
- int prevLine = -1 ;
855
- Hit* firstHitOnLine = nullptr ;
856
-
857
- for (Hit& h : hits)
858
- {
859
- int lineZero = (int )sciSend (SCI_LINEFROMPOSITION, h.pos , 0 );
860
- int lineOne = lineZero + 1 ;
861
-
862
- /* --- read raw bytes ------------------------------------ */
863
- int rawLen = (int )sciSend (SCI_LINELENGTH, lineZero, 0 );
864
- std::string raw (rawLen, ' \0 ' );
865
- sciSend (SCI_GETLINE, lineZero, (LPARAM)raw.data ());
866
- raw.resize (strnlen (raw.c_str (), rawLen));
867
- while (!raw.empty () && (raw.back () == ' \r ' || raw.back () == ' \n ' ))
868
- raw.pop_back ();
869
-
870
- /* --- trim leading blanks ------------------------------- */
871
- size_t lead = raw.find_first_not_of (" \t " );
872
- std::string_view sliceBytes =
873
- (lead == std::string::npos) ? std::string_view{}
874
- : std::string_view (raw).substr (lead);
875
-
876
- /* --- FULL slice as UTF‑8 (★) --------------------------- */
877
- const std::string sliceU8 = Encoding::bytesToUtf8 (sliceBytes, docCp);
878
- const std::wstring sliceW = Encoding::utf8ToWString (sliceU8);
879
-
880
- /* --- prefix -------------------------------------------- */
881
- std::wstring prefixW = std::wstring (INDENT_W)
882
- + L" Line " + std::to_wstring (lineOne) + L" : " ;
883
- size_t prefixU8Len = Encoding::wstringToUtf8 (prefixW).size ();
884
-
885
- /* --- byte offset of hit inside slice ------------------- */
886
- Sci_Position absTrimmed = sciSend (SCI_POSITIONFROMLINE, lineZero, 0 ) + (Sci_Position)lead;
887
- size_t relBytes = (size_t )(h.pos - absTrimmed);
888
-
889
- /* --- locate hit in UTF‑8 text (★) --------------------- */
890
- size_t hitStartInSlice = Encoding::bytesToUtf8 (
891
- sliceBytes.substr (0 , relBytes), docCp).size ();
892
- size_t hitLenU8 = Encoding::bytesToUtf8 (
893
- sliceBytes.substr (relBytes, h.length ), docCp).size ();
894
-
895
- /* --- first hit on this visual line? -------------------- */
896
- if (lineZero != prevLine)
897
- {
898
- out += prefixW + sliceW + L" \r\n " ;
899
-
900
- h.displayLineStart = (int )utf8Pos;
901
- h.numberStart = (int )(INDENT_U8 + 5 );
902
- h.numberLen = (int )std::to_string (lineOne).size ();
903
- h.matchStarts = { (int )(prefixU8Len + hitStartInSlice) };
904
- h.matchLens = { (int )hitLenU8 };
905
-
906
- utf8Pos += prefixU8Len + sliceU8.size () + 2 ;
907
- firstHitOnLine = &h;
908
- prevLine = lineZero;
909
- }
910
- else /* additional hit on same line */
911
- {
912
- firstHitOnLine->matchStarts .push_back (
913
- (int )(prefixU8Len + hitStartInSlice));
914
- firstHitOnLine->matchLens .push_back ((int )hitLenU8);
915
- h.displayLineStart = -1 ; // dummy
916
- }
917
- }
918
-
919
- hits.erase (std::remove_if (hits.begin (), hits.end (),
920
- [](const Hit& h) { return h.displayLineStart < 0 ; }),
921
- hits.end ());
922
- }
923
938
924
939
925
940
0 commit comments