forked from eranif/codelite
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathCSSCodeCompletion.cpp
More file actions
158 lines (137 loc) · 5.02 KB
/
Copy pathCSSCodeCompletion.cpp
File metadata and controls
158 lines (137 loc) · 5.02 KB
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
154
155
156
157
158
#include "CSSCodeCompletion.h"
#include "JSON.h"
#include "codelite_events.h"
#include "css.json"
#include "event_notifier.h"
#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)
: 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 (const auto& s : e.values) {
valuesSet.insert(s);
}
}
for (const wxString& v : valuesSet) {
Entry e;
e.property = v;
m_entries.push_back(e);
}
EventNotifier::Get()->Bind(wxEVT_CC_CODE_COMPLETE, &CSSCodeCompletion::OnCodeComplete, this);
}
CSSCodeCompletion::~CSSCodeCompletion()
{
EventNotifier::Get()->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 && wxWindow::FindFocus() == editor->GetCtrl() && 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;
}