1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153
|
#include "CSSCodeCompletion.h"
#include "JSON.h"
#include "codelite_events.h"
#include "css.json"
#include "globals.h"
#include "ieditor.h"
#include "webtools.h"
#include "wxCodeCompletionBox.h"
#include "wxCodeCompletionBoxEntry.hpp"
#include "wxCodeCompletionBoxManager.h"
#include <algorithm>
#include <set>
#include <wx/stc/stc.h>
#include <wx/tokenzr.h>
#include <wx/xrc/xmlres.h>
CSSCodeCompletion::CSSCodeCompletion(WebTools* plugin)
: ServiceProvider("WebTools: CSS", eServiceType::kCodeCompletion)
, m_isEnabled(true)
, m_plugin(plugin)
{
JSON root(CSS_JSON);
JSONItem arr = root.toElement();
int count = arr.arraySize();
std::set<wxString> valuesSet;
for(int i = 0; i < count; ++i) {
JSONItem entry = arr.arrayItem(i);
if(!entry.hasNamedObject("name"))
continue;
Entry e;
e.property = entry.namedObject("name").toString();
e.values = entry.namedObject("values").toArrayString();
m_entries.push_back(e);
// collect the values and make them a unique set
for(size_t i = 0; i < e.values.size(); ++i) {
valuesSet.insert(e.values.Item(i));
}
}
std::for_each(valuesSet.begin(), valuesSet.end(), [&](const wxString& v) {
Entry e;
e.property = v;
m_entries.push_back(e);
});
Bind(wxEVT_CC_CODE_COMPLETE, &CSSCodeCompletion::OnCodeComplete, this);
}
CSSCodeCompletion::~CSSCodeCompletion() { Unbind(wxEVT_CC_CODE_COMPLETE, &CSSCodeCompletion::OnCodeComplete, this); }
void CSSCodeCompletion::CssCodeComplete(IEditor* editor)
{
if(!m_isEnabled)
return;
// Perform HTML code completion
wxStyledTextCtrl* ctrl = editor->GetCtrl();
int currentLine = ctrl->GetCurrentLine();
int minPos = ctrl->PositionFromLine(currentLine);
wxChar nonWhitespaceChar = 0;
int nonWhitespaceCharPos = wxNOT_FOUND;
int curpos = ctrl->GetCurrentPos();
while((curpos > minPos)) {
nonWhitespaceChar = ctrl->GetCharAt(curpos);
switch(nonWhitespaceChar) {
case '\n':
case '\r':
case '\t':
case ' ':
break;
default:
nonWhitespaceCharPos = curpos;
break;
}
if(nonWhitespaceCharPos != wxNOT_FOUND)
break;
curpos = ctrl->PositionBefore(curpos);
}
if(nonWhitespaceCharPos != wxNOT_FOUND && nonWhitespaceChar == ':') {
// Suggest values of the given properties
wxString word = GetPreviousWord(editor, nonWhitespaceCharPos);
if(word.IsEmpty())
return;
Entry::Vec_t::const_iterator iter =
std::find_if(m_entries.begin(), m_entries.end(), [&](const Entry& e) { return (e.property == word); });
if(iter != m_entries.end()) {
wxCodeCompletionBox::BmpVec_t bitmaps;
bitmaps.push_back(wxXmlResource::Get()->LoadBitmap("code-tags"));
wxCodeCompletionBoxEntry::Vec_t entries;
const wxArrayString& values = (*iter).values;
for(size_t i = 0; i < values.size(); ++i) {
wxCodeCompletionBoxEntry::Ptr_t entry = wxCodeCompletionBoxEntry::New(values.Item(i), 0);
entries.push_back(entry);
}
wxCodeCompletionBoxManager::Get().ShowCompletionBox(editor->GetCtrl(), entries, bitmaps, 0,
editor->GetCurrentPosition(), this);
}
} else {
wxCodeCompletionBox::BmpVec_t bitmaps;
bitmaps.push_back(wxXmlResource::Get()->LoadBitmap("code-tags"));
wxCodeCompletionBoxEntry::Vec_t entries;
for(size_t i = 0; i < m_entries.size(); ++i) {
wxCodeCompletionBoxEntry::Ptr_t entry = wxCodeCompletionBoxEntry::New(m_entries.at(i).property, 0);
// entry->SetComment(m_entries.at(i).m_comment);
entries.push_back(entry);
}
wxCodeCompletionBoxManager::Get().ShowCompletionBox(
editor->GetCtrl(), entries, bitmaps, 0, editor->WordStartPos(editor->GetCurrentPosition(), false), this);
}
}
wxString CSSCodeCompletion::GetPreviousWord(IEditor* editor, int pos)
{
int lineStartPos = editor->GetCtrl()->PositionFromLine(editor->GetCtrl()->LineFromPosition(pos));
// get the line from the start up until the ":"
wxString line = editor->GetCtrl()->GetTextRange(lineStartPos, pos);
if(line.IsEmpty())
return "";
wxArrayString words = ::wxStringTokenize(line, "\r\n \t", wxTOKEN_STRTOK);
if(words.IsEmpty())
return "";
return words.Last();
}
void CSSCodeCompletion::OnCodeComplete(clCodeCompletionEvent& event)
{
event.Skip();
IEditor* editor = GetEditor(event.GetFileName());
if(editor && m_plugin->IsCSSFile(editor)) {
// CSS code completion
event.Skip(false);
CssCodeComplete(editor);
}
}
IEditor* CSSCodeCompletion::GetEditor(const wxString& filename) const
{
auto editor = clGetManager()->FindEditor(filename);
if(editor && editor == clGetManager()->GetActiveEditor()) {
return editor;
}
return nullptr;
}
|