Skip to content

Commit d8c3da6

Browse files
committed
Toggle folds on header double-click
1 parent 77af585 commit d8c3da6

File tree

1 file changed

+96
-81
lines changed

1 file changed

+96
-81
lines changed

src/ResultDock.cpp

Lines changed: 96 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -322,7 +322,85 @@ void ResultDock::formatHitsForFile(const std::wstring& wPath,
322322
formatHitsLines(sciSend, hits, out, utf8Pos);
323323
}
324324

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);
325369

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+
}
326404

327405
// --- Private Methods ---
328406

@@ -710,7 +788,6 @@ void ResultDock::applyStyling() const
710788
h.matchLens[i]);
711789
}
712790

713-
714791
LRESULT CALLBACK ResultDock::sciSubclassProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp)
715792
{
716793
extern NppData nppData;
@@ -743,10 +820,27 @@ LRESULT CALLBACK ResultDock::sciSubclassProc(HWND hwnd, UINT msg, WPARAM wp, LPA
743820
LRESULT firstVisible = ::SendMessage(hwnd, SCI_GETFIRSTVISIBLELINE, 0, 0);
744821

745822
// 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);
747825
Sci_Position pos = ::SendMessage(hwnd, SCI_POSITIONFROMPOINT, x, y);
826+
if (pos < 0) // guard for empty area
827+
return 0;
748828
int dispLine = (int)::SendMessage(hwnd, SCI_LINEFROMPOSITION, pos, 0);
749829

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+
750844
// 3) Read the raw text of that line
751845
int lineLen = (int)::SendMessage(hwnd, SCI_LINELENGTH, dispLine, 0);
752846
std::string raw(lineLen, '\0');
@@ -841,85 +935,6 @@ LRESULT CALLBACK ResultDock::sciSubclassProc(HWND hwnd, UINT msg, WPARAM wp, LPA
841935
: ::DefWindowProc(hwnd, msg, wp, lp);
842936
}
843937

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-
}
923938

924939

925940

0 commit comments

Comments
 (0)