Skip to content

Commit

Permalink
FS#420 FS#316 Rework tab trigger logic
Browse files Browse the repository at this point in the history
  • Loading branch information
vershov committed Nov 23, 2010
1 parent c55ee61 commit 1eeb6d3
Show file tree
Hide file tree
Showing 4 changed files with 49 additions and 60 deletions.
60 changes: 10 additions & 50 deletions src/EditorCtrl.cpp
Expand Up @@ -1358,49 +1358,12 @@ void EditorCtrl::Tab() {
return;
}

unsigned int pos = GetPos();
if (m_macro.IsRecording()) m_macro.Add(wxT("Tab"));

// If the tab is preceded by a word it can trigger a snippet
const unsigned int pos = GetPos();
unsigned int wordstart = pos;

// First check if we can get a trigger before first non-alnum char
cxLOCKDOC_READ(m_doc)
while (wordstart) {
const unsigned int prevchar = doc.GetPrevCharPos(wordstart);
const wxChar c = doc.GetChar(prevchar);
if (!Isalnum(c)) break;
wordstart = prevchar;
}
cxENDLOCK
if (wordstart < pos && DoTabTrigger(wordstart, pos)) return;

// If that did not give a trigger, try to first whitespace
cxLOCKDOC_READ(m_doc)
while (wordstart) {
const unsigned int prevchar = doc.GetPrevCharPos(wordstart);
const wxChar c = doc.GetChar(prevchar);
if (wxIsspace(c)) break;
wordstart = prevchar;
}
cxENDLOCK
if (wordstart < pos) {
if (DoTabTrigger(wordstart, pos)) return;

// If we still don't have a trigger, check if we are in quotes or parans
// (needed for the rare case when trigger is non-alnum)
unsigned int qstart = pos;
cxLOCKDOC_READ(m_doc)
while (qstart > wordstart) {
const unsigned int prevchar = doc.GetPrevCharPos(qstart);
const wxChar c = doc.GetChar(prevchar);
if (c == wxT('"') || c == wxT('\'') || c == wxT('(') || c == wxT('{') || c == wxT('[')) break;
qstart = prevchar;
}
cxENDLOCK
if (qstart < pos && qstart != wordstart && DoTabTrigger(qstart, pos)) return;
}

if (DoTabTrigger(pos)) return;

// If we get to here we have to insert a real tab
if (!m_parentFrame.IsSoftTabs()) { // Hard Tab
InsertChar(wxChar('\t'));
Expand Down Expand Up @@ -1429,22 +1392,19 @@ void EditorCtrl::Tab() {
Insert(indent);
}

bool EditorCtrl::DoTabTrigger(unsigned int wordstart, unsigned int wordend) {
wxASSERT(wordstart < wordend && wordend <= m_lines.GetLength());
bool EditorCtrl::DoTabTrigger(unsigned int pos) {
wxASSERT(pos <= m_lines.GetLength());

wxString trigger;
wxString strPart; // part of the current line to check trigger actions
cxLOCKDOC_READ(m_doc)
trigger = doc.GetTextPart(wordstart, wordend);
strPart = doc.GetTextPart(doc.GetLineStart(pos), pos);
cxENDLOCK

const deque<const wxString*> scope = m_syntaxstyler.GetScope(wordend);
const vector<const tmAction*> actions = m_syntaxHandler.GetActions(trigger, scope);
const deque<const wxString*> scope = m_syntaxstyler.GetScope(pos);
const vector<const tmAction*> actions = m_syntaxHandler.GetActions(strPart, scope);

if (actions.empty()) return false; // no action found for trigger

//wxLogDebug(wxT("%s (%u)"), trigger, snippets.size());
//wxLogDebug(wxT("%s"), actions[0]->content);

// Present user with a list of actions
int actionIndex = 0;
if (actions.size() > 1) {
Expand All @@ -1460,7 +1420,7 @@ bool EditorCtrl::DoTabTrigger(unsigned int wordstart, unsigned int wordend) {

// Remove the trigger
Freeze();
RawDelete(wordstart, wordend);
RawDelete(pos - actions[actionIndex]->trigger.Len(), pos);

// Do the Action
DoAction(*actions[actionIndex], NULL, true);
Expand Down
2 changes: 1 addition & 1 deletion src/EditorCtrl.h
Expand Up @@ -530,7 +530,7 @@ class EditorCtrl : public KeyHookable<wxControl>,
int ShowPopupList(wxMenu& menu);

void Tab();
bool DoTabTrigger(unsigned int wordstart, unsigned int wordend);
bool DoTabTrigger(unsigned int pos);

void DeleteSelections();
void InsertOverSelections(const wxString& text);
Expand Down
27 changes: 19 additions & 8 deletions src/tm_syntaxhandler.cpp
Expand Up @@ -29,6 +29,8 @@
#include "IAppPaths.h"
#include "IEditorDoAction.h"

bool Isalnum(wxChar c); // defined in EditorCtrl.cpp

// tinyxml includes unused vars so it can't compile with Level 4
#ifdef __WXMSW__
#pragma warning(push, 1)
Expand Down Expand Up @@ -298,7 +300,7 @@ void TmSyntaxHandler::ClearBundleActions() {
m_actions.clear();

// Release allocated triggers
for (map<const wxString, sNode<tmAction>*>::iterator t = m_actionTriggers.begin(); t != m_actionTriggers.end(); ++t) {
for (Triggers::iterator t = m_actionTriggers.begin(); t != m_actionTriggers.end(); ++t) {
delete t->second;
}
m_actionTriggers.clear();
Expand Down Expand Up @@ -742,15 +744,24 @@ void TmSyntaxHandler::GetDragActions(const deque<const wxString*>& scopes, vecto
m_dragNode.GetMatches(scopes, result, matchfun);
}

const vector<const tmAction*> TmSyntaxHandler::GetActions(const wxString& trigger, const deque<const wxString*>& scopes) const {
map<const wxString, sNode<tmAction>*>::const_iterator p = m_actionTriggers.find(trigger);
const vector<const tmAction*> TmSyntaxHandler::GetActions(
const wxString& strPart, const deque<const wxString*>& scopes) const {

if (p != m_actionTriggers.end()) {
p->second->Print();
const vector<const tmAction*>* s = (const vector<const tmAction*>*)p->second->GetMatch(scopes);
if (s) return *s;
}
Triggers::const_iterator p = m_actionTriggers.lower_bound(strPart);
wxString key = p->first;
while ((p != m_actionTriggers.end()) &&
((key[key.Len() - 1] == strPart[strPart.Len() - 1]))) {

if (!strPart.EndsWith(key)) {
} else if ((key.Len() < strPart.Len()) && (Isalnum(key[0])) &&
(Isalnum(strPart[strPart.Len() - key.Len() - 1]))) {
} else {
const vector<const tmAction*>* s = (const vector<const tmAction*>*)p->second->GetMatch(scopes);
if (s) return *s;
}
++p;
key = p->first;
}
return vector<const tmAction*>();
}

Expand Down
20 changes: 19 additions & 1 deletion src/tm_syntaxhandler.h
Expand Up @@ -191,6 +191,24 @@ template <class T> class sNode {
void Tokenize(const wxString& scope, wxArrayString& words) const;
};

// Compare class for triggers
class TriggerCompare {
public:
bool operator()(const wxString& a, const wxString &b) {
size_t a_len = a.Len(), b_len = b.Len();
for (size_t i = 1; i <= a_len; i++) {
if (b_len < i) return true;
if (a[a_len - i] > b[b_len - i]) {
return false;
} else if (a[a_len - i] < b[b_len - i]) {
return true;
}
}
return false;
};
};
typedef std::map<const wxString, sNode<tmAction>*, class TriggerCompare> Triggers;

class TmSyntaxHandler:
public ITmThemeHandler,
public ITmLoadBundles,
Expand Down Expand Up @@ -368,7 +386,7 @@ class TmSyntaxHandler:
sNode<tmAction> m_actionNode;
sNode<tmDragCommand> m_dragNode;
std::map<const wxString, tmAction*> m_actions;
std::map<const wxString, sNode<tmAction>*> m_actionTriggers;
Triggers m_actionTriggers;
std::map<unsigned int, wxString> m_menuActions;
wxMenu* m_bundleMenu;
unsigned int m_nextMenuID;
Expand Down

0 comments on commit 1eeb6d3

Please sign in to comment.