diff --git a/lspdiagresultslog.cpp b/lspdiagresultslog.cpp new file mode 100644 index 0000000..a76334c --- /dev/null +++ b/lspdiagresultslog.cpp @@ -0,0 +1,296 @@ +/* + * This file is part of the Code::Blocks IDE and licensed under the GNU Lesser General Public License, version 3 + * http://www.gnu.org/licenses/lgpl-3.0.html + * + * $Revision$ + * $Id$ + * $HeadURL$ + */ + +//#include "sdk_precomp.h" gets not used because `EXPORT_LIB' not defined [-Winvalid-pch] error +#if not defined(__WXMSW__) + #include "sdk.h" // needed for wxTextCtr/listLoggerCtrl on linux +#endif + +//#ifndef CB_PRECOMP + #include + #include + #include + #include "manager.h" + #include "editormanager.h" + #include "cbeditor.h" +//#endif +#include +#include +#include "wx/xrc/xmlres.h" + +#include +#include +#include + +#include "cbstyledtextctrl.h" +#include "lspdiagresultslog.h" + +// three additional includes to support codeActions (aka fix available) +#include "globals.h" +#include "logmanager.h" +#include "infowindow.h" + + +namespace +{ + const int ID_List = wxNewId(); + const int idMenuIgnoredMsgs = wxNewId(); + // CodeAction Fix Available + const int idMenuApplyFixIfAvailable = XRCID("idMenuApplyFixIfAvailable"); + const int idRequestCodeActionAppy = XRCID("idRequestCodeActionApply"); + +} + +BEGIN_EVENT_TABLE(LSPDiagnosticsResultsLog, wxEvtHandler) +// +END_EVENT_TABLE() + +// ---------------------------------------------------------------------------- +LSPDiagnosticsResultsLog::LSPDiagnosticsResultsLog(const wxArrayString& titles_in, wxArrayInt& widths_in, wxArrayString& aIgnoredMsgs) +// ---------------------------------------------------------------------------- + : ListCtrlLogger(titles_in, widths_in), + rUsrIgnoredDiagnostics(aIgnoredMsgs) //reference to client persistent wxArrayString of log ignored messages + +{ + Connect(idMenuIgnoredMsgs, -1, wxEVT_COMMAND_MENU_SELECTED, + (wxObjectEventFunction) (wxEventFunction) (wxCommandEventFunction) + &LSPDiagnosticsResultsLog::OnSetIgnoredMsgs); + + Bind(wxEVT_COMMAND_MENU_SELECTED, &LSPDiagnosticsResultsLog::OnApplyFixIfAvailable, this, idMenuApplyFixIfAvailable); + +} +// ---------------------------------------------------------------------------- +wxEvtHandler* LSPDiagnosticsResultsLog::FindEventHandler(wxEvtHandler* pEvtHdlr) +// ---------------------------------------------------------------------------- +{ + wxEvtHandler* pFoundEvtHdlr = Manager::Get()->GetAppWindow()->GetEventHandler(); + + while (pFoundEvtHdlr != nullptr) + { + if (pFoundEvtHdlr == pEvtHdlr) + return pFoundEvtHdlr; + pFoundEvtHdlr = pFoundEvtHdlr->GetNextHandler(); + } + return nullptr; +} +// ---------------------------------------------------------------------------- +LSPDiagnosticsResultsLog::~LSPDiagnosticsResultsLog() +// ---------------------------------------------------------------------------- +{ + //dtor + Disconnect(idMenuIgnoredMsgs, -1, wxEVT_COMMAND_MENU_SELECTED, + (wxObjectEventFunction) (wxEventFunction) (wxCommandEventFunction) + &LSPDiagnosticsResultsLog::OnSetIgnoredMsgs); + Unbind(wxEVT_COMMAND_MENU_SELECTED, &LSPDiagnosticsResultsLog::OnApplyFixIfAvailable, this, idMenuApplyFixIfAvailable); + if (FindEventHandler(this)) + Manager::Get()->GetAppWindow()->RemoveEventHandler(this); +} +// ---------------------------------------------------------------------------- +wxWindow* LSPDiagnosticsResultsLog::CreateControl(wxWindow* parent) +// ---------------------------------------------------------------------------- +{ + ListCtrlLogger::CreateControl(parent); + control->SetId(ID_List); + //Connect(ID_List, -1, wxEVT_COMMAND_LIST_ITEM_ACTIVATED, + // ^^^ a range of IDs is not necessary + Connect(ID_List, wxEVT_COMMAND_LIST_ITEM_ACTIVATED, + (wxObjectEventFunction) (wxEventFunction) (wxCommandEventFunction) + &LSPDiagnosticsResultsLog::OnDoubleClick); + Manager::Get()->GetAppWindow()->PushEventHandler(this); + m_pControl = control; + return control; +} + +// ---------------------------------------------------------------------------- +bool LSPDiagnosticsResultsLog::HasFeature(Feature::Enum feature) const +// ---------------------------------------------------------------------------- +{ + if (feature == Feature::Additional) + return true; + else + return ListCtrlLogger::HasFeature(feature); +} + +// ---------------------------------------------------------------------------- +void LSPDiagnosticsResultsLog::AppendAdditionalMenuItems(wxMenu &menu) +// ---------------------------------------------------------------------------- +{ + menu.Append(idMenuApplyFixIfAvailable, _("Apply fix if available"), _("Apply LSP fix if available")); + menu.Append(idMenuIgnoredMsgs, _("Show/Set ignore messages"), _("Show/Set ignored messages")); +} + +// ---------------------------------------------------------------------------- +void LSPDiagnosticsResultsLog::FocusEntry(size_t index) +// ---------------------------------------------------------------------------- +{ + if (index < (size_t)control->GetItemCount()) + { + control->SetItemState(index, wxLIST_STATE_FOCUSED | wxLIST_STATE_SELECTED, wxLIST_STATE_FOCUSED | wxLIST_STATE_SELECTED); + control->EnsureVisible(index); + //-SyncEditor(index); + } +} + +// ---------------------------------------------------------------------------- +void LSPDiagnosticsResultsLog::SyncEditor(int selIndex) +// ---------------------------------------------------------------------------- +{ + wxFileName filename(control->GetItemText(selIndex)); + wxString file; + if (not filename.Exists()) return; + if (!filename.IsAbsolute()) + filename.MakeAbsolute(m_Base); + file = filename.GetFullPath(); + + wxListItem li; + li.m_itemId = selIndex; + li.m_col = 1; + li.m_mask = wxLIST_MASK_TEXT; + control->GetItem(li); + long line = 0; + li.m_text.ToLong(&line); + cbEditor* ed = Manager::Get()->GetEditorManager()->Open(file); + if (!line || !ed) + return; + + line -= 1; + ed->Activate(); + ed->GotoLine(line); + + if (cbStyledTextCtrl* ctrl = ed->GetControl()) { + ctrl->EnsureVisible(line); + } +} + +// ---------------------------------------------------------------------------- +void LSPDiagnosticsResultsLog::OnDoubleClick(cb_unused wxCommandEvent& event) +// ---------------------------------------------------------------------------- +{ + // go to the relevant file/line + if (control->GetSelectedItemCount() == 0) + return; + + // find selected item index + int index = control->GetNextItem(-1, + wxLIST_NEXT_ALL, + wxLIST_STATE_SELECTED); + + SyncEditor(index); +} // end of OnDoubleClick + +// ---------------------------------------------------------------------------- +void LSPDiagnosticsResultsLog::OnSetIgnoredMsgs(wxCommandEvent& event) +// ---------------------------------------------------------------------------- +{ + // create dialog showing LSP ignored textDocument/publishDiagnostic messages + // Log lines contain filename|lineNumber|msg + //eg., F:\usr\Proj\Clangd_Client\plugin\plugins\LSPclient\lspdiagresultslog.cpp|16|note:In included file: definition of builtin function '__rdtsc'| + + wxString annoyingMsg = _("Setting a diagnostic as ignored may cause the associated statement to also\n" + "be ignored for references, declarations, implementations etc."); + + AnnoyingDialog annoyingDlg(_("Set ignored log messages"), annoyingMsg, wxART_INFORMATION, AnnoyingDialog::OK); + annoyingDlg.ShowModal(); + + int cnt = GetItemsCount(); //log lines + //-if (not cnt) return; + wxArrayString aryOfLogItems; + for (int ii=0; iiGetAppWindow(), rUsrIgnoredDiagnostics, true); + wxCheckListBox* pdlglst = XRCCTRL(dlg, "lstItems", wxCheckListBox); + for (size_t ii=0; iiAppend(aryOfLogItems[ii]); + if (dlg.ShowModal() == wxID_OK) + { + rUsrIgnoredDiagnostics.Empty(); + rUsrIgnoredDiagnostics = dlg.GetSelectedStrings(); + // write array of ignored messages to the config + ConfigManager* pCfgMgr = Manager::Get()->GetConfigManager("clangd_client"); + pCfgMgr->Write("ignored_diagnostics", rUsrIgnoredDiagnostics); + } + return; +} +// ---------------------------------------------------------------------------- +void LSPDiagnosticsResultsLog::OnApplyFixIfAvailable(wxCommandEvent& event) +// ---------------------------------------------------------------------------- +{ + // When user right-clicks a log entry that contains "(fix available)" + // parse the log line to get filename and line number. + // Issue an event to Clgdcompletion to apply the fix which was stored + // in the Parsers FixesAvailable map.vectors. + + LogManager* pLogMgr = Manager::Get()->GetLogManager(); + wxUnusedVar(pLogMgr); //maybe unused + + wxListCtrl* pListControl = control; + wxString selectedLineText = wxString(); + long itemIndex = -1; + + while ((itemIndex = pListControl->GetNextItem(itemIndex, + wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED)) != wxNOT_FOUND) + { + // Got the selected item index + selectedLineText = GetItemAsText(itemIndex); + if (not (selectedLineText.Contains(" (fix available) ") or (selectedLineText.Contains("(fixes available)")))) + { + wxString msg = wxString::Format(_("No Fix available for logLine(%d)"), int(itemIndex) ); + InfoWindow::Display(_("NO fix"), msg); + return; + } + } + if (selectedLineText.empty()) return; + + // parse the line at '|' chars to get filename, lineNum text, and error text + wxArrayString lineItems = GetArrayFromString(selectedLineText, "|", /*trimSpaces*/ true); + size_t itemKnt = lineItems.GetCount(); + if (itemKnt < 3) return; + for (size_t ii=0; iiDebugLog(lineItems[ii]); // **Debugging** + if (lineItems[ii].empty()) return; + } + + // index 0:filename 1:lineNumber 2:Error text + wxString filename = lineItems[0]; + wxString lineNumStr = lineItems[1]; + wxString logText = lineItems[2]; + + // Obtain cbEditor for this file + cbEditor* pEd = Manager::Get()->GetEditorManager()->GetBuiltinEditor(filename); + if (not pEd) return; + + // Issue a "textDocument/codeAction" request to ClgdCompletion. + // This class does not have addressability to what we need (parser and FixesAvailable). + wxCommandEvent evt(wxEVT_COMMAND_MENU_SELECTED, idRequestCodeActionAppy); + evt.SetString(filename +"|"+lineNumStr+"|"+logText); + Manager::Get()->GetAppFrame()->GetEventHandler()->AddPendingEvent(evt); + + return; +}//OnApplyFixIfAvailable