diff --git a/Command.h b/Command.h index 20ede02..b6df681 100644 --- a/Command.h +++ b/Command.h @@ -98,6 +98,9 @@ enum class CommandId { // Syntax highlighting Syntax, // ":syntax on|off|reload" SetOption, // generic ":set key=value" (v1: filetype=) + // LSP + LspHover, + LspGotoDefinition, }; diff --git a/Editor.h b/Editor.h index f7010f9..5f90acd 100644 --- a/Editor.h +++ b/Editor.h @@ -450,6 +450,12 @@ public: } + // LSP helpers: trigger hover/definition at current cursor in current buffer + bool LspHoverAtCursor(); + + bool LspGotoDefinitionAtCursor(); + + // LSP: notify buffer saved (used by commands) void NotifyBufferSaved(Buffer *buf); diff --git a/GUIRenderer.cc b/GUIRenderer.cc index a607235..9dc876a 100644 --- a/GUIRenderer.cc +++ b/GUIRenderer.cc @@ -47,7 +47,6 @@ GUIRenderer::Draw(Editor &ed) ImGuiWindowFlags flags = ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoScrollbar - | ImGuiWindowFlags_NoScrollWithMouse | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoCollapse @@ -60,7 +59,7 @@ GUIRenderer::Draw(Editor &ed) ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0.0f); ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(6.f, 6.f)); - ImGui::Begin("kte", nullptr, flags); + ImGui::Begin("kte", nullptr, flags | ImGuiWindowFlags_NoScrollWithMouse); const Buffer *buf = ed.CurrentBuffer(); if (!buf) { @@ -69,7 +68,7 @@ GUIRenderer::Draw(Editor &ed) const auto &lines = buf->Rows(); // Reserve space for status bar at bottom ImGui::BeginChild("scroll", ImVec2(0, -ImGui::GetFrameHeightWithSpacing()), false, - ImGuiWindowFlags_HorizontalScrollbar | ImGuiWindowFlags_NoScrollWithMouse); + ImGuiWindowFlags_HorizontalScrollbar); // Detect click-to-move inside this scroll region ImVec2 list_origin = ImGui::GetCursorScreenPos(); float scroll_y = ImGui::GetScrollY(); @@ -109,13 +108,13 @@ GUIRenderer::Draw(Editor &ed) } // If user scrolled, update buffer offsets accordingly if (prev_scroll_y >= 0.0f && scroll_y != prev_scroll_y) { - if (Buffer *mbuf = const_cast(buf)) { + if (auto mbuf = const_cast(buf)) { mbuf->SetOffsets(static_cast(std::max(0L, scroll_top)), mbuf->Coloffs()); } } if (prev_scroll_x >= 0.0f && scroll_x != prev_scroll_x) { - if (Buffer *mbuf = const_cast(buf)) { + if (auto mbuf = const_cast(buf)) { mbuf->SetOffsets(mbuf->Rowoffs(), static_cast(std::max(0L, scroll_left))); } @@ -162,11 +161,13 @@ GUIRenderer::Draw(Editor &ed) buf->Highlighter()->PrefetchViewport(*buf, fr, rc, buf->Version()); } } - // Handle mouse click before rendering to avoid dependent on drawn items + // Handle mouse click before rendering to avoid dependency on drawn items if (ImGui::IsWindowHovered() && ImGui::IsMouseClicked(ImGuiMouseButton_Left)) { ImVec2 mp = ImGui::GetIO().MousePos; // Compute viewport-relative row so (0) is top row of the visible area - float vy_f = (mp.y - list_origin.y - scroll_y) / row_h; + // Note: list_origin is already in the scrolled space of the child window, + // so we must NOT subtract scroll_y again (would double-apply). + float vy_f = (mp.y - list_origin.y) / row_h; long vy = static_cast(vy_f); if (vy < 0) vy = 0; @@ -190,8 +191,9 @@ GUIRenderer::Draw(Editor &ed) by = 0; } - // Compute desired pixel X inside the viewport content (subtract horizontal scroll) - float px = (mp.x - list_origin.x - scroll_x); + // Compute desired pixel X inside the viewport content. + // list_origin is already scrolled; do not subtract scroll_x here. + float px = (mp.x - list_origin.x); if (px < 0.0f) px = 0.0f; @@ -254,11 +256,11 @@ GUIRenderer::Draw(Editor &ed) const std::size_t coloffs_now = buf->Coloffs(); for (std::size_t i = rowoffs; i < lines.size(); ++i) { // Capture the screen position before drawing the line - ImVec2 line_pos = ImGui::GetCursorScreenPos(); - std::string line = static_cast(lines[i]); + ImVec2 line_pos = ImGui::GetCursorScreenPos(); + auto line = static_cast(lines[i]); // Expand tabs to spaces with width=8 and apply horizontal scroll offset - const std::size_t tabw = 8; + constexpr std::size_t tabw = 8; std::string expanded; expanded.reserve(line.size() + 16); std::size_t rx_abs_draw = 0; // rendered column for drawing @@ -275,7 +277,7 @@ GUIRenderer::Draw(Editor &ed) for (auto it = std::sregex_iterator(line.begin(), line.end(), rx); it != std::sregex_iterator(); ++it) { const auto &m = *it; - std::size_t sx = static_cast(m.position()); + auto sx = static_cast(m.position()); std::size_t ex = sx + static_cast(m.length()); hl_src_ranges.emplace_back(sx, ex); } @@ -318,9 +320,9 @@ GUIRenderer::Draw(Editor &ed) continue; // fully left of view std::size_t vx0 = (rx_start > coloffs_now) ? (rx_start - coloffs_now) : 0; std::size_t vx1 = rx_end - coloffs_now; - ImVec2 p0 = ImVec2(line_pos.x + static_cast(vx0) * space_w, line_pos.y); - ImVec2 p1 = ImVec2(line_pos.x + static_cast(vx1) * space_w, - line_pos.y + line_h); + auto p0 = ImVec2(line_pos.x + static_cast(vx0) * space_w, line_pos.y); + auto p1 = ImVec2(line_pos.x + static_cast(vx1) * space_w, + line_pos.y + line_h); // Choose color: current match stronger bool is_current = has_current && sx == cur_x && ex == cur_end; ImU32 col = is_current @@ -347,7 +349,7 @@ GUIRenderer::Draw(Editor &ed) const kte::LineHighlight &lh = buf->Highlighter()->GetLine( *buf, static_cast(i), buf->Version()); // Helper to convert a src column to expanded rx position - auto src_to_rx_full = [&](std::size_t sidx) -> std::size_t { + auto src_to_rx_full = [&](const std::size_t sidx) -> std::size_t { std::size_t rx = 0; for (std::size_t k = 0; k < sidx && k < line.size(); ++k) { rx += (line[k] == '\t') ? (tabw - (rx % tabw)) : 1; @@ -369,12 +371,14 @@ GUIRenderer::Draw(Editor &ed) if (vx1 <= vx0) continue; ImU32 col = ImGui::GetColorU32(kte::SyntaxInk(sp.kind)); - ImVec2 p = ImVec2(line_pos.x + static_cast(vx0) * space_w, line_pos.y); + auto p = ImVec2(line_pos.x + static_cast(vx0) * space_w, line_pos.y); ImGui::GetWindowDrawList()->AddText( p, col, expanded.c_str() + vx0, expanded.c_str() + vx1); } - // We drew text via draw list (no layout advance). Manually advance the cursor to the next line. - ImGui::SetCursorScreenPos(ImVec2(line_pos.x, line_pos.y + line_h)); + // We drew text via draw list (no layout advance). Advance by the same amount + // ImGui uses between lines (line height + spacing) so hit-testing (which + // divides by row_h) aligns with drawing. + ImGui::SetCursorScreenPos(ImVec2(line_pos.x, line_pos.y + row_h)); } else { // No syntax: draw as one run ImGui::TextUnformatted(expanded.c_str()); @@ -417,9 +421,9 @@ GUIRenderer::Draw(Editor &ed) ImGui::GetWindowDrawList()->AddRectFilled(p0, p1, bg_col); // If a prompt is active, replace the entire status bar with the prompt text if (ed.PromptActive()) { - std::string label = ed.PromptLabel(); - std::string ptext = ed.PromptText(); - auto kind = ed.CurrentPromptKind(); + const std::string &label = ed.PromptLabel(); + std::string ptext = ed.PromptText(); + auto kind = ed.CurrentPromptKind(); if (kind == Editor::PromptKind::OpenFile || kind == Editor::PromptKind::SaveAs || kind == Editor::PromptKind::Chdir) { const char *home_c = std::getenv("HOME"); @@ -466,8 +470,8 @@ GUIRenderer::Draw(Editor &ed) float ratio = tail_sz.x / avail_px; size_t skip = ratio > 1.5f ? std::min(tail.size() - start, - (size_t) std::max( - 1, (size_t) (tail.size() / 4))) + static_cast(std::max( + 1, tail.size() / 4))) : 1; start += skip; std::string candidate = tail.substr(start); @@ -524,8 +528,7 @@ GUIRenderer::Draw(Editor &ed) left += " "; // Insert buffer position prefix "[x/N] " before filename { - std::size_t total = ed.BufferCount(); - if (total > 0) { + if (std::size_t total = ed.BufferCount(); total > 0) { std::size_t idx1 = ed.CurrentBufferIndex() + 1; // 1-based for display left += "["; left += std::to_string(static_cast(idx1)); @@ -539,7 +542,7 @@ GUIRenderer::Draw(Editor &ed) left += " *"; // Append total line count as "L" { - unsigned long lcount = static_cast(buf->Rows().size()); + auto lcount = buf->Rows().size(); left += " "; left += std::to_string(lcount); left += "L"; @@ -625,9 +628,9 @@ GUIRenderer::Draw(Editor &ed) ImGuiViewport *vp2 = ImGui::GetMainViewport(); // Desired size, min size, and margins - const ImVec2 want(800.0f, 500.0f); - const ImVec2 min_sz(240.0f, 160.0f); - const float margin = 20.0f; // space from viewport edges + constexpr ImVec2 want(800.0f, 500.0f); + constexpr ImVec2 min_sz(240.0f, 160.0f); + constexpr float margin = 20.0f; // space from viewport edges // Compute the maximum allowed size (viewport minus margins) and make sure it's not negative ImVec2 max_sz(std::max(32.0f, vp2->Size.x - 2.0f * margin), @@ -767,4 +770,4 @@ GUIRenderer::Draw(Editor &ed) ed.SetFilePickerVisible(false); } } -} \ No newline at end of file +} diff --git a/TerminalInputHandler.cc b/TerminalInputHandler.cc index bcc1000..57f6035 100644 --- a/TerminalInputHandler.cc +++ b/TerminalInputHandler.cc @@ -38,18 +38,48 @@ map_key_to_command(const int ch, MEVENT ev{}; if (getmouse(&ev) == OK) { // Mouse wheel → map to MoveUp/MoveDown one line per wheel notch + unsigned long wheel_up_mask = 0; + unsigned long wheel_dn_mask = 0; #ifdef BUTTON4_PRESSED - if (ev.bstate & (BUTTON4_PRESSED | BUTTON4_RELEASED | BUTTON4_CLICKED)) { - out = {true, CommandId::MoveUp, "", 0}; - return true; - } + wheel_up_mask |= BUTTON4_PRESSED; +#endif +#ifdef BUTTON4_RELEASED + wheel_up_mask |= BUTTON4_RELEASED; +#endif +#ifdef BUTTON4_CLICKED + wheel_up_mask |= BUTTON4_CLICKED; +#endif +#ifdef BUTTON4_DOUBLE_CLICKED + wheel_up_mask |= BUTTON4_DOUBLE_CLICKED; +#endif +#ifdef BUTTON4_TRIPLE_CLICKED + wheel_up_mask |= BUTTON4_TRIPLE_CLICKED; #endif #ifdef BUTTON5_PRESSED - if (ev.bstate & (BUTTON5_PRESSED | BUTTON5_RELEASED | BUTTON5_CLICKED)) { - out = {true, CommandId::MoveDown, "", 0}; + wheel_dn_mask |= BUTTON5_PRESSED; +#endif +#ifdef BUTTON5_RELEASED + wheel_dn_mask |= BUTTON5_RELEASED; +#endif +#ifdef BUTTON5_CLICKED + wheel_dn_mask |= BUTTON5_CLICKED; +#endif +#ifdef BUTTON5_DOUBLE_CLICKED + wheel_dn_mask |= BUTTON5_DOUBLE_CLICKED; +#endif +#ifdef BUTTON5_TRIPLE_CLICKED + wheel_dn_mask |= BUTTON5_TRIPLE_CLICKED; +#endif + if (wheel_up_mask && (ev.bstate & wheel_up_mask)) { + // Prefer viewport scrolling for wheel: page up + out = {true, CommandId::PageUp, "", 0}; + return true; + } + if (wheel_dn_mask && (ev.bstate & wheel_dn_mask)) { + // Prefer viewport scrolling for wheel: page down + out = {true, CommandId::PageDown, "", 0}; return true; } -#endif // React to left button click/press if (ev.bstate & (BUTTON1_CLICKED | BUTTON1_PRESSED | BUTTON1_RELEASED)) { char buf[64]; diff --git a/ext/json.h b/ext/json.h index 8ecaf4b..1aace96 100644 --- a/ext/json.h +++ b/ext/json.h @@ -1216,30 +1216,30 @@ JSON_HEDLEY_SUNPRO_VERSION_CHECK(8, 0, 0) || \ #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("diag_suppress 1215,1444") #elif JSON_HEDLEY_GCC_VERSION_CHECK(4, 3, 0) #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"") -#elif JSON_HEDLEY_MSVC_VERSION_CHECK(15,0,0) +#elif JSON_HEDLEY_MSVC_VERSION_CHECK(15, 0, 0) #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED __pragma(warning(disable:4996)) -#elif JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) +#elif JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1, 25, 10) #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("diag_suppress 1215,1444") #elif \ - JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ - (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ - (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ - (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ - (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ - JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ - JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) +JSON_HEDLEY_TI_VERSION_CHECK(15, 12, 0) || \ + (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4, 8, 0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ +JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5, 2, 0) || \ + (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6, 0, 0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ +JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6, 4, 0) || \ + (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4, 0, 0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ +JSON_HEDLEY_TI_CL430_VERSION_CHECK(4, 3, 0) || \ + (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7, 2, 0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ +JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7, 5, 0) || \ +JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1, 2, 0) || \ +JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2, 1, 0) #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("diag_suppress 1291,1718") -#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,13,0) && !defined(__cplusplus) +#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5, 13, 0) && !defined(__cplusplus) #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("error_messages(off,E_DEPRECATED_ATT,E_DEPRECATED_ATT_MESS)") -#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,13,0) && defined(__cplusplus) +#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5, 13, 0) && defined(__cplusplus) #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("error_messages(off,symdeprecated,symdeprecated2)") -#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) +#elif JSON_HEDLEY_IAR_VERSION_CHECK(8, 0, 0) #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("diag_suppress=Pe1444,Pe1215") -#elif JSON_HEDLEY_PELLES_VERSION_CHECK(2,90,0) +#elif JSON_HEDLEY_PELLES_VERSION_CHECK(2, 90, 0) #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("warn(disable:2241)") #else #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED @@ -1258,19 +1258,19 @@ JSON_HEDLEY_SUNPRO_VERSION_CHECK(8, 0, 0) || \ #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("diag_suppress 1675") #elif JSON_HEDLEY_GCC_VERSION_CHECK(4, 3, 0) #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("GCC diagnostic ignored \"-Wunknown-pragmas\"") -#elif JSON_HEDLEY_MSVC_VERSION_CHECK(15,0,0) +#elif JSON_HEDLEY_MSVC_VERSION_CHECK(15, 0, 0) #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS __pragma(warning(disable:4068)) #elif \ - JSON_HEDLEY_TI_VERSION_CHECK(16,9,0) || \ - JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,0,0) || \ - JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ - JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,3,0) +JSON_HEDLEY_TI_VERSION_CHECK(16, 9, 0) || \ +JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8, 0, 0) || \ +JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1, 2, 0) || \ +JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2, 3, 0) #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("diag_suppress 163") -#elif JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,0,0) +#elif JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8, 0, 0) #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("diag_suppress 163") -#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) +#elif JSON_HEDLEY_IAR_VERSION_CHECK(8, 0, 0) #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("diag_suppress=Pe161") -#elif JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) +#elif JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1, 25, 10) #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("diag_suppress 161") #else #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS @@ -1283,26 +1283,26 @@ JSON_HEDLEY_SUNPRO_VERSION_CHECK(8, 0, 0) || \ #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("clang diagnostic ignored \"-Wunknown-attributes\"") #elif JSON_HEDLEY_GCC_VERSION_CHECK(4, 6, 0) #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"") -#elif JSON_HEDLEY_INTEL_VERSION_CHECK(17,0,0) +#elif JSON_HEDLEY_INTEL_VERSION_CHECK(17, 0, 0) #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("warning(disable:1292)") -#elif JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) +#elif JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021, 1, 0) #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES __pragma(warning(disable:1292)) -#elif JSON_HEDLEY_MSVC_VERSION_CHECK(19,0,0) +#elif JSON_HEDLEY_MSVC_VERSION_CHECK(19, 0, 0) #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES __pragma(warning(disable:5030)) -#elif JSON_HEDLEY_PGI_VERSION_CHECK(20,7,0) +#elif JSON_HEDLEY_PGI_VERSION_CHECK(20, 7, 0) #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("diag_suppress 1097,1098") -#elif JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) +#elif JSON_HEDLEY_PGI_VERSION_CHECK(17, 10, 0) #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("diag_suppress 1097") -#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,14,0) && defined(__cplusplus) +#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5, 14, 0) && defined(__cplusplus) #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("error_messages(off,attrskipunsup)") #elif \ - JSON_HEDLEY_TI_VERSION_CHECK(18,1,0) || \ - JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,3,0) || \ - JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) +JSON_HEDLEY_TI_VERSION_CHECK(18, 1, 0) || \ +JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8, 3, 0) || \ +JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1, 2, 0) #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("diag_suppress 1173") -#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) +#elif JSON_HEDLEY_IAR_VERSION_CHECK(8, 0, 0) #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("diag_suppress=Pe1097") -#elif JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) +#elif JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1, 25, 10) #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("diag_suppress 1097") #else #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES @@ -1328,9 +1328,9 @@ JSON_HEDLEY_SUNPRO_VERSION_CHECK(8, 0, 0) || \ #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION _Pragma("clang diagnostic ignored \"-Wunused-function\"") #elif JSON_HEDLEY_GCC_VERSION_CHECK(3, 4, 0) #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION _Pragma("GCC diagnostic ignored \"-Wunused-function\"") -#elif JSON_HEDLEY_MSVC_VERSION_CHECK(1,0,0) +#elif JSON_HEDLEY_MSVC_VERSION_CHECK(1, 0, 0) #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION __pragma(warning(disable:4505)) -#elif JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) +#elif JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1, 25, 10) #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION _Pragma("diag_suppress 3142") #else #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION @@ -1635,7 +1635,7 @@ JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1, 2, 0) || \ JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2, 1, 0) || \ JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1, 25, 10) #define JSON_HEDLEY_PRINTF_FORMAT(string_idx,first_to_check) __attribute__((__format__(__printf__, string_idx, first_to_check))) -#elif JSON_HEDLEY_PELLES_VERSION_CHECK(6,0,0) +#elif JSON_HEDLEY_PELLES_VERSION_CHECK(6, 0, 0) #define JSON_HEDLEY_PRINTF_FORMAT(string_idx,first_to_check) __declspec(vaformat(printf,string_idx,first_to_check)) #else #define JSON_HEDLEY_PRINTF_FORMAT(string_idx,first_to_check) @@ -1679,21 +1679,21 @@ JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1, 25, 10) # define JSON_HEDLEY_UNLIKELY(expr) __builtin_expect (!!(expr), 0 ) #elif \ (JSON_HEDLEY_HAS_BUILTIN(__builtin_expect) && !defined(JSON_HEDLEY_INTEL_CL_VERSION)) || \ - JSON_HEDLEY_GCC_VERSION_CHECK(3,0,0) || \ - JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ - (JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,15,0) && defined(__cplusplus)) || \ - JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ - JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ - JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ - JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,7,0) || \ - JSON_HEDLEY_TI_CL430_VERSION_CHECK(3,1,0) || \ - JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,1,0) || \ - JSON_HEDLEY_TI_CL6X_VERSION_CHECK(6,1,0) || \ - JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ - JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ - JSON_HEDLEY_TINYC_VERSION_CHECK(0,9,27) || \ - JSON_HEDLEY_CRAY_VERSION_CHECK(8,1,0) || \ - JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) +JSON_HEDLEY_GCC_VERSION_CHECK(3, 0, 0) || \ +JSON_HEDLEY_INTEL_VERSION_CHECK(13, 0, 0) || \ + (JSON_HEDLEY_SUNPRO_VERSION_CHECK(5, 15, 0) && defined(__cplusplus)) || \ +JSON_HEDLEY_ARM_VERSION_CHECK(4, 1, 0) || \ +JSON_HEDLEY_IBM_VERSION_CHECK(10, 1, 0) || \ +JSON_HEDLEY_TI_VERSION_CHECK(15, 12, 0) || \ +JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4, 7, 0) || \ +JSON_HEDLEY_TI_CL430_VERSION_CHECK(3, 1, 0) || \ +JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6, 1, 0) || \ +JSON_HEDLEY_TI_CL6X_VERSION_CHECK(6, 1, 0) || \ +JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1, 2, 0) || \ +JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2, 1, 0) || \ +JSON_HEDLEY_TINYC_VERSION_CHECK(0, 9, 27) || \ +JSON_HEDLEY_CRAY_VERSION_CHECK(8, 1, 0) || \ +JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1, 25, 10) # define JSON_HEDLEY_PREDICT(expr, expected, probability) \ (((probability) >= 0.9) ? __builtin_expect((expr), (expected)) : (JSON_HEDLEY_STATIC_CAST(void, expected), (expr))) # define JSON_HEDLEY_PREDICT_TRUE(expr, probability) \ @@ -1742,11 +1742,11 @@ JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1, 2, 0) || \ JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2, 1, 0) || \ JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1, 25, 10) #define JSON_HEDLEY_MALLOC __attribute__((__malloc__)) -#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,10,0) +#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5, 10, 0) #define JSON_HEDLEY_MALLOC _Pragma("returns_new_memory") #elif \ - JSON_HEDLEY_MSVC_VERSION_CHECK(14,0,0) || \ - JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) +JSON_HEDLEY_MSVC_VERSION_CHECK(14, 0, 0) || \ +JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021, 1, 0) #define JSON_HEDLEY_MALLOC __declspec(restrict) #else #define JSON_HEDLEY_MALLOC @@ -1776,13 +1776,13 @@ JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2, 1, 0) || \ JSON_HEDLEY_PGI_VERSION_CHECK(17, 10, 0) || \ JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1, 25, 10) # define JSON_HEDLEY_PURE __attribute__((__pure__)) -#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,10,0) +#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5, 10, 0) # define JSON_HEDLEY_PURE _Pragma("does_not_write_global_data") #elif defined(__cplusplus) && \ ( \ - JSON_HEDLEY_TI_CL430_VERSION_CHECK(2,0,1) || \ - JSON_HEDLEY_TI_CL6X_VERSION_CHECK(4,0,0) || \ - JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) \ +JSON_HEDLEY_TI_CL430_VERSION_CHECK(2, 0, 1) || \ +JSON_HEDLEY_TI_CL6X_VERSION_CHECK(4, 0, 0) || \ +JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1, 2, 0) \ ) # define JSON_HEDLEY_PURE _Pragma("FUNC_IS_PURE;") #else @@ -1814,7 +1814,7 @@ JSON_HEDLEY_PGI_VERSION_CHECK(17, 10, 0) || \ JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1, 25, 10) #define JSON_HEDLEY_CONST __attribute__((__const__)) #elif \ - JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,10,0) +JSON_HEDLEY_SUNPRO_VERSION_CHECK(5, 10, 0) #define JSON_HEDLEY_CONST _Pragma("no_side_effect") #else #define JSON_HEDLEY_CONST JSON_HEDLEY_PURE @@ -1900,20 +1900,20 @@ JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1, 25, 10) || \ JSON_HEDLEY_IAR_VERSION_CHECK(8, 10, 0) # define JSON_HEDLEY_ALWAYS_INLINE __attribute__((__always_inline__)) JSON_HEDLEY_INLINE #elif \ - JSON_HEDLEY_MSVC_VERSION_CHECK(12,0,0) || \ - JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) +JSON_HEDLEY_MSVC_VERSION_CHECK(12, 0, 0) || \ +JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021, 1, 0) # define JSON_HEDLEY_ALWAYS_INLINE __forceinline #elif defined(__cplusplus) && \ ( \ - JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ - JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ - JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ - JSON_HEDLEY_TI_CL6X_VERSION_CHECK(6,1,0) || \ - JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ - JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) \ +JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5, 2, 0) || \ +JSON_HEDLEY_TI_CL430_VERSION_CHECK(4, 3, 0) || \ +JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6, 4, 0) || \ +JSON_HEDLEY_TI_CL6X_VERSION_CHECK(6, 1, 0) || \ +JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1, 2, 0) || \ +JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2, 1, 0) \ ) # define JSON_HEDLEY_ALWAYS_INLINE _Pragma("FUNC_ALWAYS_INLINE;") -#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) +#elif JSON_HEDLEY_IAR_VERSION_CHECK(8, 0, 0) # define JSON_HEDLEY_ALWAYS_INLINE _Pragma("inline=forced") #else # define JSON_HEDLEY_ALWAYS_INLINE JSON_HEDLEY_INLINE @@ -1944,18 +1944,18 @@ JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1, 25, 10) || \ JSON_HEDLEY_IAR_VERSION_CHECK(8, 10, 0) #define JSON_HEDLEY_NEVER_INLINE __attribute__((__noinline__)) #elif \ - JSON_HEDLEY_MSVC_VERSION_CHECK(13,10,0) || \ - JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) +JSON_HEDLEY_MSVC_VERSION_CHECK(13, 10, 0) || \ +JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021, 1, 0) #define JSON_HEDLEY_NEVER_INLINE __declspec(noinline) -#elif JSON_HEDLEY_PGI_VERSION_CHECK(10,2,0) +#elif JSON_HEDLEY_PGI_VERSION_CHECK(10, 2, 0) #define JSON_HEDLEY_NEVER_INLINE _Pragma("noinline") -#elif JSON_HEDLEY_TI_CL6X_VERSION_CHECK(6,0,0) && defined(__cplusplus) +#elif JSON_HEDLEY_TI_CL6X_VERSION_CHECK(6, 0, 0) && defined(__cplusplus) #define JSON_HEDLEY_NEVER_INLINE _Pragma("FUNC_CANNOT_INLINE;") -#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) +#elif JSON_HEDLEY_IAR_VERSION_CHECK(8, 0, 0) #define JSON_HEDLEY_NEVER_INLINE _Pragma("inline=never") -#elif JSON_HEDLEY_COMPCERT_VERSION_CHECK(3,2,0) +#elif JSON_HEDLEY_COMPCERT_VERSION_CHECK(3, 2, 0) #define JSON_HEDLEY_NEVER_INLINE __attribute((noinline)) -#elif JSON_HEDLEY_PELLES_VERSION_CHECK(9,0,0) +#elif JSON_HEDLEY_PELLES_VERSION_CHECK(9, 0, 0) #define JSON_HEDLEY_NEVER_INLINE __declspec(noinline) #else #define JSON_HEDLEY_NEVER_INLINE @@ -2009,9 +2009,9 @@ JSON_HEDLEY_INTEL_VERSION_CHECK(13, 0, 0) || \ JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1, 25, 10) #define JSON_HEDLEY_NO_THROW __attribute__((__nothrow__)) #elif \ - JSON_HEDLEY_MSVC_VERSION_CHECK(13,1,0) || \ - JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) || \ - JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) +JSON_HEDLEY_MSVC_VERSION_CHECK(13, 1, 0) || \ +JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021, 1, 0) || \ +JSON_HEDLEY_ARM_VERSION_CHECK(4, 1, 0) #define JSON_HEDLEY_NO_THROW __declspec(nothrow) #else #define JSON_HEDLEY_NO_THROW @@ -2025,7 +2025,7 @@ JSON_HEDLEY_HAS_ATTRIBUTE(fallthrough) || \ JSON_HEDLEY_GCC_VERSION_CHECK(7, 0, 0) || \ JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1, 25, 10) #define JSON_HEDLEY_FALL_THROUGH __attribute__((__fallthrough__)) -#elif JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS(clang,fallthrough) +#elif JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS(clang, fallthrough) #define JSON_HEDLEY_FALL_THROUGH JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[clang::fallthrough]]) #elif JSON_HEDLEY_HAS_CPP_ATTRIBUTE(fallthrough) #define JSON_HEDLEY_FALL_THROUGH JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[fallthrough]]) @@ -2223,11 +2223,11 @@ JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021, 1, 0) JSON_HEDLEY_GCC_VERSION_CHECK(4, 4, 0) || \ JSON_HEDLEY_INTEL_VERSION_CHECK(13, 0, 0) # define JSON_HEDLEY_MESSAGE(msg) JSON_HEDLEY_PRAGMA(message msg) -#elif JSON_HEDLEY_CRAY_VERSION_CHECK(5,0,0) +#elif JSON_HEDLEY_CRAY_VERSION_CHECK(5, 0, 0) # define JSON_HEDLEY_MESSAGE(msg) JSON_HEDLEY_PRAGMA(_CRI message msg) -#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) +#elif JSON_HEDLEY_IAR_VERSION_CHECK(8, 0, 0) # define JSON_HEDLEY_MESSAGE(msg) JSON_HEDLEY_PRAGMA(message(msg)) -#elif JSON_HEDLEY_PELLES_VERSION_CHECK(2,0,0) +#elif JSON_HEDLEY_PELLES_VERSION_CHECK(2, 0, 0) # define JSON_HEDLEY_MESSAGE(msg) JSON_HEDLEY_PRAGMA(message(msg)) #else # define JSON_HEDLEY_MESSAGE(msg) @@ -2248,8 +2248,8 @@ JSON_HEDLEY_PGI_VERSION_CHECK(18, 4, 0) || \ JSON_HEDLEY_INTEL_VERSION_CHECK(13, 0, 0) # define JSON_HEDLEY_WARNING(msg) JSON_HEDLEY_PRAGMA(GCC warning msg) #elif \ - JSON_HEDLEY_MSVC_VERSION_CHECK(15,0,0) || \ - JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) +JSON_HEDLEY_MSVC_VERSION_CHECK(15, 0, 0) || \ +JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021, 1, 0) # define JSON_HEDLEY_WARNING(msg) JSON_HEDLEY_PRAGMA(message(msg)) #else # define JSON_HEDLEY_WARNING(msg) JSON_HEDLEY_MESSAGE(msg) @@ -3035,7 +3035,7 @@ operator<(const value_t lhs, const value_t rhs) noexcept const auto r_index = static_cast(rhs); #if JSON_HAS_THREE_WAY_COMPARISON if (l_index < order.size() && r_index < order.size()) { - return order[l_index] <=> order[r_index]; // *NOPAD* + return order[l_index] <= > order[r_index]; // *NOPAD* } return std::partial_ordering::unordered; #else @@ -3052,7 +3052,7 @@ operator<(const value_t lhs, const value_t rhs) noexcept inline bool operator<(const value_t lhs, const value_t rhs) noexcept { - return std::is_lt(lhs <=> rhs); // *NOPAD* + return std::is_lt(lhs <= > rhs); // *NOPAD* } #endif } // namespace detail @@ -3187,6 +3187,7 @@ NLOHMANN_JSON_NAMESPACE_END #include // conditional, enable_if, false_type, integral_constant, is_constructible, is_integral, is_same, remove_cv, remove_reference, true_type + #include // index_sequence, make_index_sequence, index_sequence_for // #include @@ -3400,10 +3401,10 @@ template struct iterator_traits {}; template -struct iterator_traits::value> -> -: -iterator_types {}; +struct iterator_traits::value> + > + : + iterator_types {}; template struct iterator_traits::value> > { @@ -3636,14 +3637,13 @@ struct is_getable { }; template -struct has_from_json::value> -> -{ - using serializer = typename BasicJsonType::template json_serializer; +struct has_from_json::value> + > { + using serializer = typename BasicJsonType::template json_serializer; - static constexpr bool value = - is_detected_exact::value; + static constexpr bool value = + is_detected_exact::value; }; // This trait checks if JSONSerializer::from_json(json const&) exists @@ -3652,14 +3652,13 @@ template struct has_non_default_from_json : std::false_type {}; template -struct has_non_default_from_json::value> -> -{ - using serializer = typename BasicJsonType::template json_serializer; +struct has_non_default_from_json::value> + > { + using serializer = typename BasicJsonType::template json_serializer; - static constexpr bool value = - is_detected_exact::value; + static constexpr bool value = + is_detected_exact::value; }; // This trait checks if BasicJsonType::json_serializer::to_json exists @@ -3668,14 +3667,13 @@ template struct has_to_json : std::false_type {}; template -struct has_to_json::value> -> -{ - using serializer = typename BasicJsonType::template json_serializer; +struct has_to_json::value> + > { + using serializer = typename BasicJsonType::template json_serializer; - static constexpr bool value = - is_detected_exact::value; + static constexpr bool value = + is_detected_exact::value; }; template @@ -3894,19 +3892,18 @@ struct is_compatible_object_type_impl : std::false_type {}; template struct is_compatible_object_type_impl< - BasicJsonType, CompatibleObjectType, - enable_if_t < is_detected::value && - is_detected::value> -> -{ - using object_t = typename BasicJsonType::object_t; + BasicJsonType, CompatibleObjectType, + enable_if_t::value && + is_detected::value> + > { + using object_t = typename BasicJsonType::object_t; - // macOS's is_constructible does not play well with nonesuch... - static constexpr bool value = - is_constructible::value && - is_constructible::value; + // macOS's is_constructible does not play well with nonesuch... + static constexpr bool value = + is_constructible::value && + is_constructible::value; }; template @@ -3919,27 +3916,26 @@ struct is_constructible_object_type_impl : std::false_type {}; template struct is_constructible_object_type_impl< - BasicJsonType, ConstructibleObjectType, - enable_if_t < is_detected::value && - is_detected::value> -> -{ - using object_t = typename BasicJsonType::object_t; + BasicJsonType, ConstructibleObjectType, + enable_if_t::value && + is_detected::value> + > { + using object_t = typename BasicJsonType::object_t; - static constexpr bool value = - (is_default_constructible::value && - (std::is_move_assignable::value || - std::is_copy_assignable::value) && - (is_constructible::value && - std::is_same < - typename object_t::mapped_type, - typename ConstructibleObjectType::mapped_type >::value)) || - (has_from_json::value || - has_non_default_from_json < - BasicJsonType, - typename ConstructibleObjectType::mapped_type >::value); + static constexpr bool value = + (is_default_constructible::value && + (std::is_move_assignable::value || + std::is_copy_assignable::value) && + (is_constructible::value && + std::is_same< + typename object_t::mapped_type, + typename ConstructibleObjectType::mapped_type>::value)) || + (has_from_json::value || + has_non_default_from_json< + BasicJsonType, + typename ConstructibleObjectType::mapped_type>::value); }; template @@ -3974,18 +3970,17 @@ struct is_compatible_array_type_impl : std::false_type {}; template struct is_compatible_array_type_impl< - BasicJsonType, CompatibleArrayType, - enable_if_t < - is_detected::value && - is_iterator_traits > >::value && - // special case for types like std::filesystem::path whose iterator's value_type are themselves - // c.f. https://github.com/nlohmann/json/pull/3073 - !std::is_same >::value> -> -{ - static constexpr bool value = - is_constructible>::value; + BasicJsonType, CompatibleArrayType, + enable_if_t< + is_detected::value && + is_iterator_traits > >::value && + // special case for types like std::filesystem::path whose iterator's value_type are themselves + // c.f. https://github.com/nlohmann/json/pull/3073 + !std::is_same >::value> + > { + static constexpr bool value = + is_constructible >::value; }; template @@ -4004,33 +3999,34 @@ struct is_constructible_array_type_impl< template struct is_constructible_array_type_impl< - BasicJsonType, ConstructibleArrayType, - enable_if_t < !std::is_same::value && - !is_compatible_string_type::value && - is_default_constructible::value && - (std::is_move_assignable::value || - std::is_copy_assignable::value) && - is_detected::value && - is_iterator_traits > >::value && - is_detected::value && - // special case for types like std::filesystem::path whose iterator's value_type are themselves - // c.f. https://github.com/nlohmann/json/pull/3073 - !std::is_same >::value && - is_complete_type< - detected_t >::value> -> -{ - using value_type = range_value_t; + BasicJsonType, ConstructibleArrayType, + enable_if_t::value && + !is_compatible_string_type::value && + is_default_constructible::value && + (std::is_move_assignable::value || + std::is_copy_assignable::value) && + is_detected::value && + is_iterator_traits > >::value + && + is_detected::value && + // special case for types like std::filesystem::path whose iterator's value_type are themselves + // c.f. https://github.com/nlohmann/json/pull/3073 + !std::is_same >::value && + is_complete_type< + detected_t >::value> + > { + using value_type = range_value_t; - static constexpr bool value = - std::is_same::value || - has_from_json::value || - has_non_default_from_json < - BasicJsonType, - value_type >::value; + static constexpr bool value = + std::is_same::value || + has_from_json::value || + has_non_default_from_json< + BasicJsonType, + value_type>::value; }; template @@ -4043,21 +4039,20 @@ struct is_compatible_integer_type_impl : std::false_type {}; template struct is_compatible_integer_type_impl< - RealIntegerType, CompatibleNumberIntegerType, - enable_if_t < std::is_integral::value && - std::is_integral::value && - !std::is_same::value> -> -{ - // is there an assert somewhere on overflows? - using RealLimits = std::numeric_limits; - using CompatibleLimits = std::numeric_limits; + RealIntegerType, CompatibleNumberIntegerType, + enable_if_t::value && + std::is_integral::value && + !std::is_same::value> + > { + // is there an assert somewhere on overflows? + using RealLimits = std::numeric_limits; + using CompatibleLimits = std::numeric_limits; - static constexpr auto value = - is_constructible::value && - CompatibleLimits::is_integer && - RealLimits::is_signed == CompatibleLimits::is_signed; + static constexpr auto value = + is_constructible::value && + CompatibleLimits::is_integer && + RealLimits::is_signed == CompatibleLimits::is_signed; }; template @@ -4070,12 +4065,11 @@ struct is_compatible_type_impl : std::false_type {}; template struct is_compatible_type_impl< - BasicJsonType, CompatibleType, - enable_if_t < is_complete_type::value> -> -{ - static constexpr bool value = - has_to_json::value; + BasicJsonType, CompatibleType, + enable_if_t::value> + > { + static constexpr bool value = + has_to_json::value; }; template @@ -4127,15 +4121,15 @@ struct is_comparable : std::false_type {}; // is_json_pointer_of can be removed once the deprecated function has been // removed. template -struct is_comparable::value - && std::is_constructible()( - std::declval(), std::declval()))>::value - && std::is_constructible()( - std::declval(), std::declval()))>::value -> -> -: -std::true_type {}; +struct is_comparable::value + && std::is_constructible()( + std::declval(), std::declval()))>::value + && std::is_constructible()( + std::declval(), std::declval()))>::value + > + > + : + std::true_type {}; template using detect_is_transparent = typename T::is_transparent; @@ -4835,7 +4829,8 @@ namespace std_fs = std::experimental::filesystem; NLOHMANN_JSON_NAMESPACE_END #elif JSON_HAS_FILESYSTEM #include // NOLINT(build/c++17) -NLOHMANN_JSON_NAMESPACE_BEGIN namespace detail { +NLOHMANN_JSON_NAMESPACE_BEGIN +namespace detail { namespace std_fs = std::filesystem; } // namespace detail NLOHMANN_JSON_NAMESPACE_END @@ -4947,12 +4942,9 @@ template< enable_if_t< std::is_assignable::value && is_detected_exact::value - && !std::is_same < typename BasicJsonType::string_t, StringType>::value - &&!is_json_ref::value, int> - - -= -0 + && !std::is_same::value + && !is_json_ref::value, int> = + 0 > inline void from_json(const BasicJsonType &j, StringType &s) @@ -5191,20 +5183,20 @@ from_json_inplace_array_impl(BasicJsonType &&j, template auto from_json(BasicJsonType &&j, identity_tag > tag) - -> decltype(from_json_inplace_array_impl(std::forward(j), tag, make_index_sequence < N > {} + -> decltype(from_json_inplace_array_impl(std::forward(j), tag, make_index_sequence{} -) -) + ) + ) { - if (JSON_HEDLEY_UNLIKELY(!j.is_array())) - { - JSON_THROW(type_error::create(302, concat("type must be array, but is ", j.type_name()), &j)); - } + if (JSON_HEDLEY_UNLIKELY(!j.is_array())) { + JSON_THROW(type_error::create(302, concat("type must be array, but is ", j.type_name()), &j)); + } - return from_json_inplace_array_impl(std::forward(j), tag, make_index_sequence {}); + return from_json_inplace_array_impl(std::forward(j), tag, make_index_sequence{}); } + template inline void from_json(const BasicJsonType &j, typename BasicJsonType::binary_t &bin) @@ -5328,7 +5320,7 @@ std::tuple from_json_tuple_impl(BasicJsonType &&j, identity_tag > /*unused*/, priority_tag<2> /*unused*/) { return from_json_tuple_impl_base(std::forward(j), - index_sequence_for < Args...> {}); + index_sequence_for{}); } @@ -5337,7 +5329,7 @@ inline void from_json_tuple_impl(BasicJsonType &&j, std::tuple &t, priority_tag<3> /*unused*/) { t = from_json_tuple_impl_base(std::forward(j), - index_sequence_for < Args...> {}); + index_sequence_for{}); } @@ -5356,11 +5348,8 @@ from_json(BasicJsonType &&j, TupleRelated &&t) template::value> - - -> + typename = enable_if_t::value> > inline void from_json(const BasicJsonType &j, std::map &m) { @@ -5378,11 +5367,8 @@ from_json(const BasicJsonType &j, std::map &m) template::value> - - -> + typename = enable_if_t::value> > inline void from_json(const BasicJsonType &j, std::unordered_map &m) { @@ -5407,13 +5393,13 @@ from_json(const BasicJsonType &j, std_fs::path &p) JSON_THROW(type_error::create(302, concat("type must be string, but is ", j.type_name()), &j)); } const auto &s = *j.template get_ptr(); -// Checking for C++20 standard or later can be insufficient in case the -// library support for char8_t is either incomplete or was disabled -// altogether. Use the __cpp_lib_char8_t feature test instead. + // Checking for C++20 standard or later can be insufficient in case the + // library support for char8_t is either incomplete or was disabled + // altogether. Use the __cpp_lib_char8_t feature test instead. #if defined(__cpp_lib_char8_t) && (__cpp_lib_char8_t >= 201907L) -p= std_fs::path (std::u8string_view(reinterpret_cast(s.data()), s.size())); + p = std_fs::path(std::u8string_view(reinterpret_cast(s.data()), s.size())); #else -p= std_fs::u8path (s); // accepts UTF-8 encoded std::string in C++17, deprecated in C++20 + p = std_fs::u8path(s); // accepts UTF-8 encoded std::string in C++17, deprecated in C++20 #endif } #endif @@ -5437,6 +5423,7 @@ namespace // NOLINT(cert-dcl59-cpp,fuchsia-header-anon-namespaces,google-build-n { + #endif JSON_INLINE_VARIABLE constexpr const auto &from_json = // NOLINT(misc-definitions-in-headers) detail::static_const::value; @@ -5748,7 +5735,7 @@ class tuple_element > { public: using type = decltype( - get < N > (std::declval< + get(std::declval< ::nlohmann::detail::iteration_proxy_value >())); }; #if defined(__clang__) @@ -6043,11 +6030,8 @@ to_json(BasicJsonType &j, const BoolRef &b) noexcept template::value, int> - - -= -0 + enable_if_t::value, int> = + 0 > inline void to_json(BasicJsonType &j, const CompatibleString &s) @@ -6122,13 +6106,10 @@ template::value && !is_compatible_object_type::value && !is_compatible_string_type::value && - !std::is_same < typename BasicJsonType::binary_t, CompatibleArrayType>::value && - !is_basic_json::value, - int> - - -= -0 + !std::is_same::value && + !is_basic_json::value, + int> = + 0 > inline void to_json(BasicJsonType &j, const CompatibleArrayType &arr) @@ -6182,15 +6163,13 @@ to_json(BasicJsonType &j, typename BasicJsonType::object_t &&obj) template< typename BasicJsonType, typename T, std::size_t N, - enable_if_t::value, // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays) - int> - - -= -0 + enable_if_t::value, // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays) + int> = + 0 > -inline void to_json(BasicJsonType & j, const T(&arr)[N]) // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays) +inline void +to_json(BasicJsonType &j, const T (&arr)[N]) // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays) { external_constructor::construct(j, arr); } @@ -6219,7 +6198,7 @@ template inline void to_json_tuple_impl(BasicJsonType &j, const Tuple &t, index_sequence /*unused*/) { - j = {std::get < Idx > (t)...}; + j = {std::get(t)...}; } @@ -6236,9 +6215,8 @@ template::value > {} - ) - ; + to_json_tuple_impl(j, t, make_index_sequence::value>{} + ); } #if JSON_HAS_FILESYSTEM || JSON_HAS_EXPERIMENTAL_FILESYSTEM @@ -6280,6 +6258,7 @@ namespace // NOLINT(cert-dcl59-cpp,fuchsia-header-anon-namespaces,google-build-n { + #endif JSON_INLINE_VARIABLE constexpr const auto &to_json = // NOLINT(misc-definitions-in-headers) detail::static_const::value; @@ -7015,18 +6994,18 @@ struct is_iterator_of_multibyte { }; template -struct iterator_input_adapter_factory::value> -> -{ - using iterator_type = IteratorType; - using char_type = typename std::iterator_traits::value_type; - using base_adapter_type = iterator_input_adapter; - using adapter_type = wide_string_input_adapter; +struct iterator_input_adapter_factory::value> + > { + using iterator_type = IteratorType; + using char_type = typename std::iterator_traits::value_type; + using base_adapter_type = iterator_input_adapter; + using adapter_type = wide_string_input_adapter; - static adapter_type create(IteratorType first, IteratorType last) - { - return adapter_type(base_adapter_type(std::move(first), std::move(last))); - } + + static adapter_type create(IteratorType first, IteratorType last) + { + return adapter_type(base_adapter_type(std::move(first), std::move(last))); + } }; // General purpose iterator-based input @@ -7155,11 +7134,11 @@ public: template::iterator_category, - std::random_access_iterator_tag>::value, - int> - ::type= - 0 + std::is_same::iterator_category, + std::random_access_iterator_tag>::value, + int> + ::type = + 0 > span_input_adapter(IteratorType first, IteratorType last) : ia(input_adapter(first, last)) {} @@ -8594,7 +8573,7 @@ public: for (const auto c: token_string) { if (static_cast(c) <= '\x1F') { // escape control characters - std::array < char, 9 > cs{{}}; + std::array cs{{}}; static_cast((std::snprintf)(cs.data(), cs.size(), "", static_cast(c))); // NOLINT(cppcoreguidelines-pro-type-vararg,hicpp-vararg) result += cs.data(); } else { @@ -10240,7 +10219,7 @@ private: default: // anything else is not supported (yet) { - std::array < char, 3 > cr{{}}; + std::array cr{{}}; static_cast((std::snprintf)(cr.data(), cr.size(), "%.2hhX", static_cast(element_type))); // NOLINT(cppcoreguidelines-pro-type-vararg,hicpp-vararg) const std::string cr_str{cr.data()}; return sax->parse_error(element_type_parse_position, cr_str, @@ -12704,6 +12683,7 @@ private: } else { + #endif auto *ptr = reinterpret_cast(&number); for (std::size_t i = 0; i < sz / 2; ++i) { @@ -12835,7 +12815,7 @@ private: */ std::string get_token_string() const { - std::array < char, 3 > cr{{}}; + std::array cr{{}}; static_cast((std::snprintf)(cr.data(), cr.size(), "%.2hhX", static_cast(current))); // NOLINT(cppcoreguidelines-pro-type-vararg,hicpp-vararg) return std::string{cr.data()}; } @@ -13735,7 +13715,7 @@ class iter_impl // NOLINT(cppcoreguidelines-special-member-functions,hicpp-speci // superficial check for the LegacyBidirectionalIterator named requirement static_assert(std::is_base_of::value && std::is_base_of::iterator_category > ::value, + typename std::iterator_traits::iterator_category>::value, "basic_json iterator assumes array and object type iterators satisfy the LegacyBidirectionalIterator named requirement.") ; @@ -15460,7 +15440,7 @@ public: /// @brief 3-way compares two JSON pointers template - std::strong_ordering operator<=>(const json_pointer &rhs) const noexcept // *NOPAD* + std::strong_ordering operator<=>(const json_pointer &rhs) constnoexcept // *NOPAD* { return reference_tokens <=> rhs.reference_tokens; // *NOPAD* } @@ -19299,9 +19279,9 @@ private: int> = 0> void dump_integer(NumberType x) { - static constexpr std::array - , - 100 > digits_to_99 + static constexpr std::array + , + 100> digits_to_99 { { {{'0', '0'}}, {{'0', '1'}}, {{'0', '2'}}, {{'0', '3'}}, {{'0', '4'}}, {{'0', '5'}}, @@ -20575,8 +20555,9 @@ private: begin(), end(), [this](const basic_json &j) { return j.m_parent == this; })); - - + + + } JSON_CATCH(...) {} // LCOV_EXCL_LINE #endif @@ -20698,12 +20679,11 @@ public: /// @brief create a null object /// @sa https://json.nlohmann.me/api/basic_json/basic_json/ - basic_json (std::nullptr_t = - nullptr + basic_json(std::nullptr_t = + nullptr ) - noexcept // NOLINT(bugprone-exception-escape) - : - basic_json (value_t::null) + noexcept // NOLINT(bugprone-exception-escape) + : basic_json(value_t::null) { assert_invariant(); } @@ -23653,6 +23633,7 @@ public: { + #ifdef __GNUC__ #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wfloat-equal" @@ -23685,7 +23666,7 @@ public: /// @brief comparison: 3-way /// @sa https://json.nlohmann.me/api/basic_json/operator_spaceship/ - std::partial_ordering operator<=>(const_reference rhs) const noexcept // *NOPAD* + std::partial_ordering operator<=>(const_reference rhs) constnoexcept // *NOPAD* { const_reference lhs = *this; // default_result is used if we cannot compare values. In that case, @@ -23700,7 +23681,7 @@ public: /// @sa https://json.nlohmann.me/api/basic_json/operator_spaceship/ template requires std::is_scalar_v - std::partial_ordering operator<=>(ScalarType rhs) const noexcept // *NOPAD* + std::partial_ordering operator<=>(ScalarType rhs) constnoexcept // *NOPAD* { return *this <=> basic_json(rhs); // *NOPAD* } @@ -25336,7 +25317,7 @@ operator"" _json(const char *s, std::size_t n) } #if defined(__cpp_char8_t) -JSON_HEDLEY_NON_NULL(1) +JSON_HEDLEY_NON_NULL (1) inline nlohmann::json operator""_json(const char8_t *s, std::size_t n) { @@ -25401,7 +25382,7 @@ struct less<::nlohmann::detail::value_t> ::nlohmann::detail::value_t rhs) const noexcept { #if JSON_HAS_THREE_WAY_COMPARISON - return std::is_lt(lhs <=> rhs); // *NOPAD* + return std::is_lt(lhs <= > rhs); // *NOPAD* #else return ::nlohmann::detail::operator<(lhs, rhs); #endif @@ -25416,8 +25397,8 @@ struct less<::nlohmann::detail::value_t> NLOHMANN_BASIC_JSON_TPL_DECLARATION inline void swap(nlohmann::NLOHMANN_BASIC_JSON_TPL &j1, nlohmann::NLOHMANN_BASIC_JSON_TPL &j2) noexcept( // NOLINT(readability-inconsistent-declaration-parameter-name, cert-dcl58-cpp) - is_nothrow_move_constructible::value && // NOLINT(misc-redundant-expression,cppcoreguidelines-noexcept-swap,performance-noexcept-swap) - is_nothrow_move_assignable::value) + is_nothrow_move_constructible::value && // NOLINT(misc-redundant-expression,cppcoreguidelines-noexcept-swap,performance-noexcept-swap) + is_nothrow_move_assignable::value) { j1.swap(j2); } @@ -25642,4 +25623,4 @@ using nlohmann::literals::json_literals::operator"" _json_pointer; //NOLINT(misc #undef JSON_HEDLEY_FALL_THROUGH -#endif // INCLUDE_NLOHMANN_JSON_HPP_ \ No newline at end of file +#endif // INCLUDE_NLOHMANN_JSON_HPP_ diff --git a/lsp/LspClient.h b/lsp/LspClient.h index cdb310e..8e55752 100644 --- a/lsp/LspClient.h +++ b/lsp/LspClient.h @@ -14,10 +14,11 @@ #include "Diagnostic.h" namespace kte::lsp { -// Callback types (stubs for future phases) -using CompletionCallback = std::function; -using HoverCallback = std::function; -using LocationCallback = std::function; +// Callback types for initial language features +// If error is non-empty, the result may be default-constructed/empty +using CompletionCallback = std::function; +using HoverCallback = std::function; +using LocationCallback = std::function & result, const std::string & error)>; class LspClient { public: @@ -39,7 +40,7 @@ public: virtual void didSave(const std::string &uri) = 0; - // Language Features (not yet implemented) + // Language Features (initial) virtual void completion(const std::string &, Position, CompletionCallback) {} diff --git a/lsp/LspManager.cc b/lsp/LspManager.cc index 3628d6a..dfbd60b 100644 --- a/lsp/LspManager.cc +++ b/lsp/LspManager.cc @@ -371,7 +371,27 @@ LspManager::requestHover(Buffer *buffer, Position pos, HoverCallback callback) lsp_debug_file("hover pos convert: L%d C%d -> L%d C%d", pos.line, pos.character, p16.line, p16.character); } - client->hover(uri, p16, std::move(callback)); + // Wrap the callback to convert any returned range from UTF-16 (wire) -> UTF-8 (editor) + HoverCallback wrapped = [this, uri, provider, cb = std::move(callback)](const HoverResult &res16, + const std::string &err) { + if (!cb) + return; + if (!res16.range.has_value()) { + cb(res16, err); + return; + } + HoverResult res8 = res16; + res8.range = toUtf8(uri, *res16.range, provider); + if (debug_) { + const auto &r16 = *res16.range; + const auto &r8 = *res8.range; + lsp_debug_file("hover range convert: L%d %d-%d -> L%d %d-%d", + r16.start.line, r16.start.character, r16.end.character, + r8.start.line, r8.start.character, r8.end.character); + } + cb(res8, err); + }; + client->hover(uri, p16, std::move(wrapped)); } } @@ -396,7 +416,29 @@ LspManager::requestDefinition(Buffer *buffer, Position pos, LocationCallback cal lsp_debug_file("definition pos convert: L%d C%d -> L%d C%d", pos.line, pos.character, p16.line, p16.character); } - client->definition(uri, p16, std::move(callback)); + // Wrap callback to convert Location ranges from UTF-16 (wire) -> UTF-8 (editor) + LocationCallback wrapped = [this, uri, provider, cb = std::move(callback)]( + const std::vector &locs16, + const std::string &err) { + if (!cb) + return; + std::vector locs8; + locs8.reserve(locs16.size()); + for (const auto &l: locs16) { + Location x = l; + x.range = toUtf8(uri, l.range, provider); + if (debug_) { + lsp_debug_file("definition range convert: L%d %d-%d -> L%d %d-%d", + l.range.start.line, l.range.start.character, + l.range.end.character, + x.range.start.line, x.range.start.character, + x.range.end.character); + } + locs8.push_back(std::move(x)); + } + cb(locs8, err); + }; + client->definition(uri, p16, std::move(wrapped)); } } diff --git a/lsp/LspProcessClient.cc b/lsp/LspProcessClient.cc index a27e2dc..ca5beed 100644 --- a/lsp/LspProcessClient.cc +++ b/lsp/LspProcessClient.cc @@ -482,6 +482,8 @@ LspProcessClient::handleIncoming(const std::string &json) if (method == "window/showMessage") { const auto itParams = j.find("params"); if (debug_ &&itParams + + != j.end() && itParams->is_object() @@ -662,9 +664,46 @@ LspProcessClient::completion(const std::string &uri, Position pos, CompletionCal params["position"]["line"] = pos.line; params["position"]["character"] = pos.character; sendRequest("textDocument/completion", params, - [cb = std::move(cb)](const nlohmann::json &/*result*/, const nlohmann::json * /*error*/) { + [cb = std::move(cb)](const nlohmann::json &result, const nlohmann::json *error) { + CompletionList out{}; + std::string err; + if (error) { + if (auto itMsg = error->find("message"); + itMsg != error->end() && itMsg->is_string()) + err = itMsg->get(); + else + err = "LSP error"; + } else { + auto parseItem = [](const nlohmann::json &j) -> CompletionItem { + CompletionItem it{}; + if (auto il = j.find("label"); il != j.end() && il->is_string()) + it.label = il->get(); + if (auto idt = j.find("detail"); idt != j.end() && idt->is_string()) + it.detail = idt->get(); + if (auto ins = j.find("insertText"); ins != j.end() && ins->is_string()) + it.insertText = ins->get(); + return it; + }; + if (result.is_array()) { + for (const auto &ji: result) { + if (ji.is_object()) + out.items.push_back(parseItem(ji)); + } + } else if (result.is_object()) { + if (auto ii = result.find("isIncomplete"); + ii != result.end() && ii->is_boolean()) + out.isIncomplete = ii->get(); + if (auto itms = result.find("items"); + itms != result.end() && itms->is_array()) { + for (const auto &ji: *itms) { + if (ji.is_object()) + out.items.push_back(parseItem(ji)); + } + } + } + } if (cb) - cb(); + cb(out, err); }); } @@ -677,9 +716,67 @@ LspProcessClient::hover(const std::string &uri, Position pos, HoverCallback cb) params["position"]["line"] = pos.line; params["position"]["character"] = pos.character; sendRequest("textDocument/hover", params, - [cb = std::move(cb)](const nlohmann::json &/*result*/, const nlohmann::json * /*error*/) { + [cb = std::move(cb)](const nlohmann::json &result, const nlohmann::json *error) { + HoverResult out{}; + std::string err; + if (error) { + if (auto itMsg = error->find("message"); + itMsg != error->end() && itMsg->is_string()) + err = itMsg->get(); + else + err = "LSP error"; + } else if (!result.is_null()) { + auto appendText = [&](const std::string &s) { + if (!out.contents.empty()) + out.contents.push_back('\n'); + out.contents += s; + }; + if (result.is_object()) { + if (auto itC = result.find("contents"); itC != result.end()) { + if (itC->is_string()) { + appendText(itC->get()); + } else if (itC->is_object()) { + if (auto itV = itC->find("value"); + itV != itC->end() && itV->is_string()) + appendText(itV->get()); + } else if (itC->is_array()) { + for (const auto &el: *itC) { + if (el.is_string()) + appendText(el.get()); + else if (el.is_object()) { + if (auto itV = el.find("value"); + itV != el.end() && itV->is_string()) + appendText(itV->get()); + } + } + } + } + if (auto itR = result.find("range"); + itR != result.end() && itR->is_object()) { + Range r{}; + if (auto s = itR->find("start"); + s != itR->end() && s->is_object()) { + if (auto il = s->find("line"); + il != s->end() && il->is_number_integer()) + r.start.line = *il; + if (auto ic = s->find("character"); + ic != s->end() && ic->is_number_integer()) + r.start.character = *ic; + } + if (auto e = itR->find("end"); e != itR->end() && e->is_object()) { + if (auto il = e->find("line"); + il != e->end() && il->is_number_integer()) + r.end.line = *il; + if (auto ic = e->find("character"); + ic != e->end() && ic->is_number_integer()) + r.end.character = *ic; + } + out.range = r; + } + } + } if (cb) - cb(); + cb(out, err); }); } @@ -692,9 +789,77 @@ LspProcessClient::definition(const std::string &uri, Position pos, LocationCallb params["position"]["line"] = pos.line; params["position"]["character"] = pos.character; sendRequest("textDocument/definition", params, - [cb = std::move(cb)](const nlohmann::json &/*result*/, const nlohmann::json * /*error*/) { + [cb = std::move(cb)](const nlohmann::json &result, const nlohmann::json *error) { + std::vector out; + std::string err; + auto parseRange = [](const nlohmann::json &jr) -> Range { + Range r{}; + if (!jr.is_object()) + return r; + if (auto s = jr.find("start"); s != jr.end() && s->is_object()) { + if (auto il = s->find("line"); il != s->end() && il->is_number_integer()) + r.start.line = *il; + if (auto ic = s->find("character"); + ic != s->end() && ic->is_number_integer()) + r.start.character = *ic; + } + if (auto e = jr.find("end"); e != jr.end() && e->is_object()) { + if (auto il = e->find("line"); il != e->end() && il->is_number_integer()) + r.end.line = *il; + if (auto ic = e->find("character"); + ic != e->end() && e->is_number_integer()) + r.end.character = *ic; + } + return r; + }; + auto pushLocObj = [&](const nlohmann::json &jo) { + Location loc{}; + if (auto iu = jo.find("uri"); iu != jo.end() && iu->is_string()) + loc.uri = iu->get(); + if (auto ir = jo.find("range"); ir != jo.end()) + loc.range = parseRange(*ir); + out.push_back(std::move(loc)); + }; + if (error) { + if (auto itMsg = error->find("message"); + itMsg != error->end() && itMsg->is_string()) + err = itMsg->get(); + else + err = "LSP error"; + } else if (!result.is_null()) { + if (result.is_object()) { + if (result.contains("uri") && result.contains("range")) { + pushLocObj(result); + } else if (result.contains("targetUri")) { + Location loc{}; + if (auto tu = result.find("targetUri"); + tu != result.end() && tu->is_string()) + loc.uri = tu->get(); + if (auto tr = result.find("targetRange"); tr != result.end()) + loc.range = parseRange(*tr); + out.push_back(std::move(loc)); + } + } else if (result.is_array()) { + for (const auto &el: result) { + if (el.is_object()) { + if (el.contains("uri")) { + pushLocObj(el); + } else if (el.contains("targetUri")) { + Location loc{}; + if (auto tu = el.find("targetUri"); + tu != el.end() && tu->is_string()) + loc.uri = tu->get(); + if (auto tr = el.find("targetRange"); + tr != el.end()) + loc.range = parseRange(*tr); + out.push_back(std::move(loc)); + } + } + } + } + } if (cb) - cb(); + cb(out, err); }); } diff --git a/lsp/LspTypes.h b/lsp/LspTypes.h index 23df3cc..7d8586b 100644 --- a/lsp/LspTypes.h +++ b/lsp/LspTypes.h @@ -28,6 +28,28 @@ struct TextDocumentContentChangeEvent { std::optional range; // if not set, represents full document change std::string text; // new text for the given range }; + +// Minimal feature result types for phase 1 +struct CompletionItem { + std::string label; + std::optional detail; // optional extra info + std::optional insertText; // if present, use instead of label +}; + +struct CompletionList { + bool isIncomplete = false; + std::vector items; +}; + +struct HoverResult { + std::string contents; // concatenated plaintext/markdown for now + std::optional range; // optional range +}; + +struct Location { + std::string uri; + Range range; +}; } // namespace kte::lsp #endif // KTE_LSP_TYPES_H \ No newline at end of file diff --git a/main.cc b/main.cc index 080f3de..247321e 100644 --- a/main.cc +++ b/main.cc @@ -30,6 +30,7 @@ PrintUsage(const char *prog) std::cerr << "Usage: " << prog << " [OPTIONS] [files]\n" << "Options:\n" << " -c, --chdir DIR Change working directory before opening files\n" + << " -d, --debug Enable LSP debug logging\n" << " -g, --gui Use GUI frontend (if built)\n" << " -t, --term Use terminal (ncurses) frontend [default]\n" << " -h, --help Show this help and exit\n" @@ -43,11 +44,6 @@ main(const int argc, const char *argv[]) Editor editor; // Wire up LSP manager (no diagnostic UI yet; frontends may provide later) kte::lsp::LspManager lspMgr(&editor, nullptr); - // Enable LSP debug logging if KTE_LSP_DEBUG is set - if (const char *dbg = std::getenv("KTE_LSP_DEBUG"); dbg && *dbg) { - lspMgr.setDebugLogging(true); - std::fprintf(stderr, "[kte][lsp] debug logging enabled via KTE_LSP_DEBUG\n"); - } editor.SetLspManager(&lspMgr); // CLI parsing using getopt_long @@ -55,11 +51,13 @@ main(const int argc, const char *argv[]) bool req_term = false; bool show_help = false; bool show_version = false; + bool lsp_debug = false; std::string nwd; static struct option long_opts[] = { {"chdir", required_argument, nullptr, 'c'}, + {"debug", no_argument, nullptr, 'd'}, {"gui", no_argument, nullptr, 'g'}, {"term", no_argument, nullptr, 't'}, {"help", no_argument, nullptr, 'h'}, @@ -69,11 +67,14 @@ main(const int argc, const char *argv[]) int opt; int long_index = 0; - while ((opt = getopt_long(argc, const_cast(argv), "c:gthV", long_opts, &long_index)) != -1) { + while ((opt = getopt_long(argc, const_cast(argv), "c:dgthV", long_opts, &long_index)) != -1) { switch (opt) { case 'c': nwd = optarg; break; + case 'd': + lsp_debug = true; + break; case 'g': req_gui = true; break; @@ -106,6 +107,16 @@ main(const int argc, const char *argv[]) (void) req_term; // suppress unused warning when GUI is not compiled in #endif + // Apply LSP debug setting strictly based on -d flag + lspMgr.setDebugLogging(lsp_debug); + if (lsp_debug) { + // Ensure LSP subprocess client picks up debug via environment + ::setenv("KTE_LSP_DEBUG", "1", 1); + } else { + // Prevent environment from enabling debug implicitly + ::unsetenv("KTE_LSP_DEBUG"); + } + // Determine frontend #if !defined(KTE_BUILD_GUI) if (req_gui) { @@ -122,6 +133,7 @@ main(const int argc, const char *argv[]) } else { + // Default depends on build target: kge defaults to GUI, kte to terminal #if defined(KTE_DEFAULT_GUI) use_gui = true;