mirror of https://github.com/buggins/dlangide.git
code completion improvements
This commit is contained in:
parent
09cb25ada9
commit
2f05223bea
2
dub.json
2
dub.json
|
@ -12,7 +12,7 @@
|
||||||
"stringImportPaths": ["views", "views/res", "views/res/i18n", "views/res/mdpi", "views/res/hdpi"],
|
"stringImportPaths": ["views", "views/res", "views/res/i18n", "views/res/mdpi", "views/res/hdpi"],
|
||||||
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"dlangui": "==0.9.24",
|
"dlangui": "==0.9.25",
|
||||||
"dcd": "~>0.9.0-alpha4"
|
"dcd": "~>0.9.0-alpha4"
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -513,6 +513,34 @@ class DSourceEdit : SourceEdit, EditableContentMarksChangeListener {
|
||||||
window.update();
|
window.update();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected CompletionPopupMenu _completionPopupMenu;
|
||||||
|
protected PopupWidget _completionPopup;
|
||||||
|
|
||||||
|
dstring identPrefixUnderCursor() {
|
||||||
|
dstring line = _content[_caretPos.line];
|
||||||
|
if (_caretPos.pos > line.length)
|
||||||
|
return null;
|
||||||
|
int end = _caretPos.pos;
|
||||||
|
int start = end;
|
||||||
|
while (start >= 0) {
|
||||||
|
dchar prevChar = start > 0 ? line[start - 1] : 0;
|
||||||
|
if (!isIdentChar(prevChar))
|
||||||
|
break;
|
||||||
|
start--;
|
||||||
|
}
|
||||||
|
if (start >= end)
|
||||||
|
return null;
|
||||||
|
return line[start .. end].dup;
|
||||||
|
}
|
||||||
|
|
||||||
|
void closeCompletionPopup(CompletionPopupMenu completion) {
|
||||||
|
if (!_completionPopup || _completionPopupMenu !is completion)
|
||||||
|
return;
|
||||||
|
_completionPopup.close();
|
||||||
|
_completionPopup = null;
|
||||||
|
_completionPopupMenu = null;
|
||||||
|
}
|
||||||
|
|
||||||
void showCompletionPopup(dstring[] suggestions, string[] icons) {
|
void showCompletionPopup(dstring[] suggestions, string[] icons) {
|
||||||
|
|
||||||
if(suggestions.length == 0) {
|
if(suggestions.length == 0) {
|
||||||
|
@ -525,32 +553,102 @@ class DSourceEdit : SourceEdit, EditableContentMarksChangeListener {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
MenuItem completionPopupItems = new MenuItem(null);
|
dstring prefix = identPrefixUnderCursor();
|
||||||
//Add all the suggestions.
|
_completionPopupMenu = new CompletionPopupMenu(this, suggestions, icons, prefix);
|
||||||
foreach(int i, dstring suggestion ; suggestions) {
|
int yOffset = font.height;
|
||||||
string iconId;
|
_completionPopup = window.showPopup(_completionPopupMenu, this, PopupAlign.Point | PopupAlign.Right,
|
||||||
if (i < icons.length)
|
|
||||||
iconId = icons[i];
|
|
||||||
auto action = new Action(IDEActions.InsertCompletion, suggestion);
|
|
||||||
action.iconId = iconId;
|
|
||||||
completionPopupItems.add(action);
|
|
||||||
}
|
|
||||||
completionPopupItems.updateActionState(this);
|
|
||||||
|
|
||||||
PopupMenu popupMenu = new PopupMenu(completionPopupItems);
|
|
||||||
popupMenu.menuItemAction = this;
|
|
||||||
popupMenu.maxHeight(400);
|
|
||||||
popupMenu.selectItem(0);
|
|
||||||
|
|
||||||
PopupWidget popup = window.showPopup(popupMenu, this, PopupAlign.Point | PopupAlign.Right,
|
|
||||||
textPosToClient(_caretPos).left + left + _leftPaneWidth,
|
textPosToClient(_caretPos).left + left + _leftPaneWidth,
|
||||||
textPosToClient(_caretPos).top + top + margins.top);
|
textPosToClient(_caretPos).top + top + margins.top + yOffset);
|
||||||
popup.setFocus();
|
_completionPopup.setFocus();
|
||||||
popup.popupClosed = delegate(PopupWidget source) { setFocus(); };
|
_completionPopup.popupClosed = delegate(PopupWidget source) {
|
||||||
popup.flags = PopupFlags.CloseOnClickOutside;
|
setFocus();
|
||||||
|
_completionPopup = null;
|
||||||
|
};
|
||||||
|
_completionPopup.flags = PopupFlags.CloseOnClickOutside;
|
||||||
|
|
||||||
Log.d("Showing popup at ", textPosToClient(_caretPos).left, " ", textPosToClient(_caretPos).top);
|
Log.d("Showing popup at ", textPosToClient(_caretPos).left, " ", textPosToClient(_caretPos).top);
|
||||||
window.update();
|
window.update();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// returns true if character is valid ident character
|
||||||
|
bool isIdentChar(dchar ch) {
|
||||||
|
return (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || (ch >= '0' && ch <= '9') || ch == '_';
|
||||||
|
}
|
||||||
|
|
||||||
|
/// returns true if all characters are valid ident chars
|
||||||
|
bool isIdentText(dstring s) {
|
||||||
|
foreach(ch; s)
|
||||||
|
if (!isIdentChar(ch))
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
class CompletionPopupMenu : PopupMenu {
|
||||||
|
protected dstring _initialPrefix;
|
||||||
|
protected dstring _prefix;
|
||||||
|
protected dstring[] _suggestions;
|
||||||
|
protected string[] _icons;
|
||||||
|
protected MenuItem _items;
|
||||||
|
protected DSourceEdit _editor;
|
||||||
|
this(DSourceEdit editor, dstring[] suggestions, string[] icons, dstring initialPrefix) {
|
||||||
|
_initialPrefix = initialPrefix;
|
||||||
|
_prefix = initialPrefix.dup;
|
||||||
|
_editor = editor;
|
||||||
|
_suggestions = suggestions;
|
||||||
|
_icons = icons;
|
||||||
|
_items = updateItems();
|
||||||
|
super(_items);
|
||||||
|
menuItemAction = _editor;
|
||||||
|
maxHeight(400);
|
||||||
|
selectItem(0);
|
||||||
|
}
|
||||||
|
MenuItem updateItems() {
|
||||||
|
MenuItem res = new MenuItem();
|
||||||
|
foreach(int i, dstring suggestion ; _suggestions) {
|
||||||
|
if (_prefix.length && !suggestion.startsWith(_prefix))
|
||||||
|
continue;
|
||||||
|
string iconId;
|
||||||
|
if (i < _icons.length)
|
||||||
|
iconId = _icons[i];
|
||||||
|
auto action = new Action(IDEActions.InsertCompletion, suggestion);
|
||||||
|
action.iconId = iconId;
|
||||||
|
res.add(action);
|
||||||
|
}
|
||||||
|
res.updateActionState(_editor);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
/// handle keys
|
||||||
|
override bool onKeyEvent(KeyEvent event) {
|
||||||
|
if (event.action == KeyAction.Text) {
|
||||||
|
_prefix ~= event.text;
|
||||||
|
MenuItem newItems = updateItems();
|
||||||
|
if (newItems.subitemCount == 0) {
|
||||||
|
// no matches anymore
|
||||||
|
_editor.onKeyEvent(event);
|
||||||
|
_editor.closeCompletionPopup(this);
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
_editor.onKeyEvent(event);
|
||||||
|
menuItems = newItems;
|
||||||
|
selectItem(0);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} else if (event.action == KeyAction.KeyDown && event.keyCode == KeyCode.BACK && event.noModifiers) {
|
||||||
|
if (_prefix.length > _initialPrefix.length) {
|
||||||
|
_prefix.length = _prefix.length - 1;
|
||||||
|
MenuItem newItems = updateItems();
|
||||||
|
_editor.onKeyEvent(event);
|
||||||
|
menuItems = newItems;
|
||||||
|
selectItem(0);
|
||||||
|
} else {
|
||||||
|
_editor.onKeyEvent(event);
|
||||||
|
_editor.closeCompletionPopup(this);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
} else if (event.action == KeyAction.KeyDown && event.keyCode == KeyCode.RETURN) {
|
||||||
|
} else if (event.action == KeyAction.KeyDown && event.keyCode == KeyCode.SPACE) {
|
||||||
|
}
|
||||||
|
return super.onKeyEvent(event);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue