Skip to content

Instantly share code, notes, and snippets.

@ssddi456
Last active December 15, 2015 10:09
Show Gist options
  • Save ssddi456/5243915 to your computer and use it in GitHub Desktop.
Save ssddi456/5243915 to your computer and use it in GitHub Desktop.
autoComplete for ace usage: autocomplete( aceediter )
.ace-autocomplete-dialog{
position:absolute;
top:0;left:0;
min-width:200px;
max-height:196px;
overflow:hidden;
font-size:12px;
display:none;
box-shadow:0 0 5px 1px rgba(0, 0, 0, 0.3);
background:#E8E8E8;
z-index:1000;
ul{
list-style:none;margin:0;padding:0;
}
.autocomplete-item {
padding:2px 8px;
margin:0;
background:#fff;
border-bottom:1px solid rgba(0, 0, 0, 0.1);
border-top:1px solid rgba(255, 255, 255, 0.8);
cursor:pointer;
color: gray;
strong{
color:#000;
}
}
.autocomplete-selected {
background-image:-webkit-linear-gradient(bottom,#337CBC 0%, #4091D8 100%);
background-image:-moz-linear-gradient(bottom,#337CBC 0%, #4091D8 100%);
background-image:linear-gradient(bottom,#337CBC 0%, #4091D8 100%);
color:lightblue;
strong{
color:#fff;
}
}
}
define([
'./autocomplete-javascript.js'
],function( autocompletelist ) {
function sugSource ( curToken, curTokens ) {
var token = curToken.value;
if( curTokens.length > 2 ){
console.log( curTokens[curToken.index - 1], curTokens[curToken.index - 2] );
if(curTokens[curToken.index - 1].value == '.' ){
var preNs = curTokens[curToken.index - 2].value;
return autocompletelist.getSource(preNs,token);
}
return autocompletelist.getIdentifier(token);
}
return autocompletelist.getGlobal(token);
};
function matcher ( query, source ) {
var query = query.value;
if( query == source ){
return;
}
var lastpos = 0, i, j, srclen = source.length, c, sc, res= '';
for(i=0, len = query.length;i<len;i++){
c = query.charAt(i);
for(j = lastpos;j<srclen;j++){
sc = source.charAt(j);
if( sc == c){
lastpos = j+1;
res += '<strong>'+ sc +'</strong>';
break;
} else {
res += sc;
}
}
if(j == srclen){
return false;
}
}
return res+source.slice(lastpos);
}
function getCursorLeftWordStart ( editor, pos ) {
var leftOfCursor = editor.session.getLine( pos.row ).slice( 0, pos.column );
leftOfCursor = leftOfCursor.split('').reverse().join('');
var index = editor.selection.$shortWordEndIndex(leftOfCursor);
var ret = {row:pos.row,column: (pos.column - index) || 0};
if(ret.column < 0 ){
ret.column = 0
}
return ret;
}
function getCursorRightWordStart ( editor, pos ) {
var line = editor.session.getLine( pos.row )
var rightOfCursor = line.slice( pos.column );
var index = editor.selection.$shortWordEndIndex(rightOfCursor);
var ret = {row:pos.row,column: pos.column + index};
if(ret.column > line.length ){
ret.column = line.length;
}
return ret;
}
function getCursorLeftTokenStart (editor, pos) {
// body...
}
function getCursorRightTokenStart (argument) {
// body...
}
var autocompleteMode = true;
var autocomplete = {};
var $autocompleteui;
var matches = [];
var selected;
function setSelected (id ) {
selected = {
text : matches[id],
idx : id
};
}
autocomplete.isActive =function () {
return autocompleteMode;
}
autocomplete.startAutoComplete = function () {
autocompleteMode = true;
this.updateUI.apply(this,arguments);
this.editor.keyBinding.addKeyboardHandler( this.keyHandler );
};
autocomplete.endAutoComplete = function () {
autocompleteMode = false;
matches = [];
selected = undefined;
this.editor.keyBinding.removeKeyboardHandler( this.keyHandler );
this.hideUI();
};
autocomplete.showUI = function () {
if( !$autocompleteui ){
this.initUI();
this.showUI = function () {
var editor = this.editor;
var session = editor.session;
var cursorPos = editor.selection.lead;
var curToken = session.getTokenAt(cursorPos.row, cursorPos.column);
var $content = $(editor.renderer.content);
var coffset = $content.offset();
var height = editor.renderer.lineHeight;
var width = editor.renderer.characterWidth;
$autocompleteui.show().css({
top : coffset.top + height * (cursorPos.row+1),
left : coffset.left + width * (curToken.start+2)
});
};
this.showUI();
}
};
autocomplete.updateUI = function (curToken, curTokens) {
var source = sugSource(curToken, curTokens);
matches = [];
var highLight = source.reduce(function ( pre, cur ) {
var ret = matcher(curToken, cur);
if(ret){
pre.push('<li>'+ret+'</li>');
matches.push(cur);
}
return pre;
},[]);
if(!matches.length){
this.endAutoComplete();
return;
} else {
selected = undefined;
}
this.showUI();
$autocompleteui.html( '<ul>' + highLight.join('') + '</ul>' );
}
autocomplete.hideUI = function () {
$autocompleteui && $autocompleteui.hide();
};
autocomplete.leftBoundCheck = function(e) {
var cursorPos = e.editor.selection.lead;
// line start
if(cursorPos.column==0 && cursorPos.row!=0){
this.endAutoComplete();
return;
}
var curTokenStartPos = getCursorLeftWordStart(e.editor, cursorPos);
if(curTokenStartPos.column == cursorPos.column-1 ){
this.endAutoComplete();
}
};
autocomplete.rightBoundCheck = function(e) {
var editor = e.editor;
var cursorPos = editor.selection.lead;
var session = editor.session;
// line end
if(cursorPos.column == session.getLine(cursorPos.row).length &&
cursorPos.row != session.doc.$lines.length
){
this.endAutoComplete();
return;
}
var curTokenStartPos = getCursorRightWordStart(editor, cursorPos);
if(curTokenStartPos.column == cursorPos.column ){
this.endAutoComplete();
}
};
autocomplete.nextHint = function(e) {
if(matches.length){
var end = matches.length - 1;
var items = $autocompleteui.find('li');
if ( selected && selected.idx != end ){
// clear cur
var idx = selected.idx;
items.eq(idx).removeClass('autocomplete-selected');
idx = idx + 1;
// show next
setSelected(idx);
items.eq(idx).addClass('autocomplete-selected');
} else {
// reposition to the first
items.last().removeClass('autocomplete-selected');
setSelected(0);
items.first().addClass('autocomplete-selected');
}
e.preventDefault();
}
};
autocomplete.prevHint = function(e) {
if(matches.length){
var end = matches.length - 1;
var items = $autocompleteui.find('li');
if ( selected && selected.idx != 0 ){
// clear cur
var idx = selected.idx;
items.eq(idx).removeClass('autocomplete-selected');
// show next
idx = idx-1;
setSelected(idx);
items.eq(idx).addClass('autocomplete-selected');
} else {
// reposition to end
items.first().removeClass('autocomplete-selected');
setSelected( end );
items.last().addClass('autocomplete-selected');
}
e.preventDefault();
}
};
autocomplete.confirm = function(e) {
var editor = e.editor;
if(selected){
var stext = selected.text;
var cursor = editor.selection.lead;
var end = getCursorRightWordStart(editor,cursor);
if( cursor.column != end.column ){
editor.navigateWordRight();
}
editor.removeWordLeft();
editor.insert(stext);
setTimeout(this.endAutoComplete.bind(this));
} else {
this.endAutoComplete();
}
e.preventDefault();
};
autocomplete.initUI = function () {
$autocompleteui = $('<div class="ace-autocomplete-dialog"></div>').appendTo(document.body);
}
autocomplete.init = function( editor ) {
this.editor = editor;
var self = this;
console.log( autocompletelist.identifiers.getAllIdentifiers(editor) );
editor.on('change',function(e) {
// to update identifiers
var edata = e.data;
// remove current
if(edata.action == 'insertText' || edata.action == 'removeText') {
if( edata.text !='\n' ){
autocompletelist.identifiers.removeIdentifersByLine(editor,edata.range.end.row);
} else {
// deal with line end
autocompletelist.identifiers.removeIdentifersByLine(editor,edata.range.start.row);
autocompletelist.identifiers.removeIdentifersByLine(editor,edata.range.end.row);
}
} else if( edata.action == 'removeLines'){
for(var i = edata.range.start.row,len=edata.range.end.row;i<len+1;i--){
autocompletelist.identifiers.removeIdentifersByLine(editor,i);
}
}
// insert new ones
if(edata.action == 'insertText' || edata.action =='removeText' ){
if( edata.text !='\n' ){
autocompletelist.identifiers.addIdentifersByLine(editor,edata.range.end.row);
} else {
// deal with line end
autocompletelist.identifiers.addIdentifersByLine(editor,edata.range.start.row);
autocompletelist.identifiers.addIdentifersByLine(editor,edata.range.end.row);
}
} else if(edata.action =='insertLines'){
for(var i = edata.range.start.row,len=edata.range.end.row;i<len+1;i--){
autocompletelist.identifiers.addIdentifersByLine(editor,i);
}
}
// build inline token context
var session = editor.getSession();
var cursorPos = editor.selection.lead;
var curTokens = session.getTokens(cursorPos.row);
var curToken;
var n = 0, index=0;
while(n <cursorPos.column && curTokens[index]){
n+= curTokens[index].value.length;
index++;
}
if(n >= cursorPos.column){
curToken = curTokens[--index];
curToken && (curToken.index = index);
}
if( !curToken ){
this.endAutoComplete();
return;
}
// start autocomplete at second char
if ( (curToken.type == 'identifier' ||
curToken.type == 'variable.language' ||
curToken.type == 'keyword' )&&
curToken.value.length > 2
){
if (this.isActive()){
this.updateUI(curToken,curTokens);
} else{
this.startAutoComplete(curToken,curTokens);
}
} else {
this.endAutoComplete();
}
}.bind(autocomplete));
// navigate key controls
editor.commands.on('exec',function (e) {
if(!self.isActive()){
return;
}
var key = e.args;
if( key in autocompleteCommands){
} else if ( e.command.bindKey ){
if( typeof e.command.bindKey == 'string' ){
key = e.command.bindKey;
} else {
key = e.command.bindKey.win;
}
}
if( !(key in autocompleteCommands )){
return;
}
autocompleteCommands[key].apply(self,arguments);
});
var autocompleteCommands = {
'Left' : self.leftBoundCheck,
'Right': self.rightBoundCheck,
'Down' : self.nextHint,
'Up' : self.prevHint,
'\n' : self.confirm
};
this.cancelCommand = [{
name: "exitAutoComplete",
bindKey: "esc",
exec: function(editor) {
self.endAutoComplete();
},
readonly: true
}];
this.keyHandler = new (editor.commands.constructor)( "win", this.cancelCommand);
}
return autocomplete;
});
define([
'./weakmap.js'
],function function_name ( Weakmap) {
var funcs =
["shift",
"showModelessDialog",
"showModalDialog",
"showHelp",
"scrollX",
"scrollByPages",
"scrollByLines",
"scrollBy",
"scrollY",
"scrollTo",
"scroll",
"stopzzzz",
"strike",
"sin",
"sizeToContent",
"sidebar",
"signText",
"sort",
"sup",
"substring",
"substr",
"sub",
"splice",
"split",
"send",
"setResizable",
"setRequestHeader",
"setMinutes",
"setMilliseconds",
"setMonth",
"setSeconds",
"setHotKeys",
"setHours",
"setYear",
"setCursor",
"setTimeout",
"setTime",
"setInterval",
"setZOptions",
"setDate",
"setUTCMinutes",
"setUTCMilliseconds",
"setUTCMonth",
"setUTCSeconds",
"setUTCHours",
"setUTCDate",
"setUTCFullYear",
"setFullYear",
"setActive",
"search",
"sqrt",
"slice",
"savePreferences",
"small",
"home",
"handleEvent",
"navigate",
"charCodeAt",
"charAt",
"cos",
"concat",
"contextual",
"confirm",
"compile",
"ceil",
"clearTimeout",
"clearInterval",
"clear",
"captureEvents",
"call",
"createStyleSheet",
"createPopup",
"createEventObject",
"toGMTString",
"toString",
"toSource",
"toUTCString",
"toUpperCase",
"toLocaleString",
"toLowerCase",
"test",
"tan",
"taintEnabled",
"taint",
"isNaN",
"isFinite",
"indexOf",
"italics",
"disableExternalCapture",
"dump",
"detachEvent",
"unshift",
"untaint",
"unescape",
"unwatch",
"updateCommands",
"join",
"javaEnabled",
"pop",
"pow",
"push",
"plugins.refresh",
"paddings",
"parseInt",
"parseFloat",
"parse",
"print",
"prompt",
"preference",
"escape",
"enableExternalCapture",
"eval",
"elementFromPoint",
"exp",
"execScript",
"execCommand",
"exec",
"valueOf",
"UTC",
"queryCommandState",
"queryCommandIndeterm",
"queryCommandEnabled",
"queryCommandValue",
"find",
"fileModifiedDate",
"fileSize",
"fileCreatedDate",
"fileUpdatedDate",
"fixed",
"fontsize",
"fontcolor",
"forward",
"floor",
"fromCharCode",
"watch",
"link",
"load",
"log",
"lastIndexOf",
"asin",
"anchor",
"acos",
"attachEvent",
"atob",
"atan2",
"atan",
"apply",
"alert",
"abs",
"abort",
"round",
"routeEvents",
"resizeBy",
"resizeTo",
"recalc",
"returnValue",
"replace",
"reverse",
"reload",
"releaseCapture",
"releaseEvents",
"random",
"go",
"getResponseHeader",
"getMinutes",
"getMilliseconds",
"getMonth",
"getSeconds",
"getSelection",
"getHours",
"getYear",
"getTimezoneOffset",
"getTime",
"getDay",
"getDate",
"getUTCMinutes",
"getUTCMilliseconds",
"getUTCMonth",
"getUTCSeconds",
"getUTCHours",
"getUTCDay",
"getUTCDate",
"getUTCFullYear",
"getFullYear",
"getAttention",
"getAllResponseHeaders",
"min",
"moveBy",
"moveBelow",
"moveToAbsolute",
"moveTo",
"moveAbove",
"mergeAttributes",
"match",
"margins",
"max",
"btoa",
"big",
"bold",
"borderWidths",
"blink",
"back"]
var doms=
["substringData",
"submit",
"splitText",
"setNamedItem",
"setAttributeNode",
"setAttribute",
"select",
"hasChildNodes",
"hasFeature",
"namedItem",
"click",
"close",
"cloneNode",
"createComment",
"createCDATASection",
"createCaption",
"createTHead",
"createTextNode",
"createTFoot",
"createDocumentFragment",
"createProcessingInstruction",
"createEntityReference",
"createElement",
"createAttribute",
"tabIndex",
"insertRow",
"insertBefore",
"insertCell",
"insertData",
"item",
"open",
"deleteRow",
"deleteCell",
"deleteCaption",
"deleteTHead",
"deleteTFoot",
"deleteData",
"focus",
"writeln",
"write",
"add",
"appendChild",
"appendData",
"reset",
"replaceChild",
"replaceData",
"removeNamedItem",
"removeChild",
"removeAttributeNode",
"removeAttribute",
"remove",
"getNamedItem",
"getElementsByName",
"getElementsByTagName",
"getElementById",
"getAttributeNode",
"getAttribute",
"blur"]
var consts =
["systemLanguage",
"scripts",
"scrollbars",
"screenX",
"screenY",
"screenTop",
"screenLeft",
"styleSheets",
"style",
"statusText",
"statusbar",
"status",
"siblingBelow",
"siblingAbove",
"source",
"suffixes",
"securityPolicy",
"security",
"selection",
"self",
"history",
"hostname",
"host",
"hash",
"hasFocus",
"y",
"XMLDocument",
"XSLDocument",
"next",
"namespaces",
"namespaceURI",
"nameProp",
"MIN_VALUE",
"MAX_VALUE",
"characterSet",
"constructor",
"controllers",
"cookieEnabled",
"colorDepth",
"components",
"complete",
"current",
"cpuClass",
"clipboardData",
"clip",
"clientInformation",
"closed",
"classes",
"callee",
"caller",
"crypto",
"toolbar",
"top",
"textTransform",
"textIndent",
"textDecoration",
"textAlign",
"tags",
"SQRT1_2",
"SQRT2",
"innerHeight",
"innerWidth",
"input",
"ids",
"ignoreCase",
"zIndex",
"oscpu",
"onreadystatechange",
"onLine",
"outerHeight",
"outerWidth",
"opsProfile",
"opener",
"offscreenBuffering",
"NEGATIVE_INFINITY",
"display",
"dialogHeight",
"dialogTop",
"dialogWidth",
"dialogLeft",
"dialogArguments",
"directories",
"description",
"defaultStatus",
"defaultChecked",
"defaultCharset",
"defaultView",
"userProfile",
"userLanguage",
"userAgent",
"uniqueID",
"undefined",
"updateInterval",
"_content",
"pixelDepth",
"port",
"personalbar",
"pkcs11",
"plugins",
"platform",
"pathname",
"paddingRight",
"paddingBottom",
"paddingTop",
"paddingLeft",
"parentWindow",
"parentLayer",
"parent",
"pageXOffset",
"pageX",
"pageYOffset",
"pageY",
"protocol",
"prototype",
"productSub",
"product",
"prompter",
"previous",
"prefix",
"encoding",
"enabledPlugin",
"external",
"expando",
"embeds",
"visibility",
"vendorSub",
"vendor",
"vLinkcolor",
"URLUnencoded",
"PI",
"POSITIVE_INFINITY",
"filename",
"fontSize",
"fontFamily",
"fontWeight",
"formName",
"frames",
"frameElement",
"fgColor",
"E",
"whiteSpace",
"listStyleType",
"lineHeight",
"linkColor",
"locationbar",
"location",
"localName",
"lowsrc",
"length",
"leftContext",
"left",
"lastModified",
"lastMatch",
"lastIndex",
"lastParen",
"layers",
"layerX",
"language",
"appMinorVersion",
"appName",
"appCodeName",
"appCore",
"appVersion",
"availHeight",
"availTop",
"availWidth",
"availLeft",
"all",
"arity",
"arguments",
"aLinkcolor",
"above",
"rightContext",
"right",
"responseXML",
"responseText",
"readyState",
"global",
"x",
"mimeTypes",
"multiline",
"menubar",
"marginRight",
"marginBottom",
"marginTop",
"marginLeft",
"LN10",
"LN2",
"LOG10E",
"LOG2E",
"bottom",
"borderWidth",
"borderRightWidth",
"borderBottomWidth",
"borderStyle",
"borderColor",
"borderTopWidth",
"borderLeftWidth",
"bufferDepth",
"below",
"backgroundColor",
"backgroundImage",
"null",
"Infinity",
"NaN",
"undefined"]
var Gobj =
["Array",
"Boolean",
"Date",
"Function",
"Iterator",
"Number",
"Object",
"RegExp",
"String",
"Proxy",
"Namespace",
"QName",
"XML",
"XMLList",
"ArrayBuffer",
"Float32Array",
"Float64Array",
"Int16Array",
"Int32Array",
"Int8Array",
"Uint16Array",
"Uint32Array",
"Uint8Array",
"Uint8ClampedArray",
"Error",
"EvalError",
"InternalError",
"RangeError",
"ReferenceError",
"StopIteration",
"SyntaxError",
"TypeError",
"URIError",
"decodeURI",
"decodeURIComponent",
"encodeURI",
"encodeURIComponent",
"eval",
"isFinite",
"isNaN",
"parseFloat",
"parseInt",
"JSON",
"Math",
"this",
"arguments",
"prototype",
"window",
"document"];
var objlist= {} // name: childArray
var namespaces = [];
var unIm = [
Object.prototype,
Function.prototype,
Array.prototype,
RegExp.prototype,
String.prototype
];
function addKeyToWords ( name, obj, depth ) {
var list;
if( depth > 10){
return;
}
if( namespaces.indexOf (name) == -1){
namespaces.push(name);
list = objlist[name] = [];
} else {
list = objlist[name];
}
depth = depth || 1;
for(var k in obj){
if(list.indexOf(k)===-1){
list.push(k);
if( _.isObject ( obj[k] ) ){
addKeyToWords( k, obj[k], depth+1);
if( unIm.indexOf(obj[k].__proto__) != -1 ){
addKeyToWords( k, obj[k].__proto__, depth+1 );
}
}
}
}
}
addKeyToWords ( 'window', window );
function filterSource ( token, list ) {
var first = token.charAt(0);
var sec = token.charAt(1);
return list.filter(function (word) {
var fi = word.indexOf(first);
if(fi == -1){
return false;
}
var si = word.indexOf(sec,first+1);
if(si == -1 ){
return false;
}
return true
});
}
var identifiers = new Weakmap();
var identifiersArray = [];
identifiers.getIdentifiersByLine = function( editor, line ) {
var tokens = editor.session.getTokens(line);
var identifier = tokens.filter(function(token) {
return token.type == 'identifier';
});
console.log( 'get', identifier );
return identifier;
}
identifiers.getAllIdentifiers = function( editor ) {
var self = this;
return editor.session.doc.$lines.reduce(function(pre,cur,idx) {
return pre.concat(self.getIdentifiersByLine(editor, idx));
},[]);
}
identifiers.addIdentifer = function( identifier ) {
if( this.has(identifier.value) ){
this.set(identifier.value, this.get(identifier.value)+1);
}else {
this.set(identifier.value, 1 );
}
}
identifiers.removeIdentifier = function( identifier ) {
if( this.has(identifier.value) ){
var remain = this.get(identifier.value)-1;
if(remain<=0){
this.remove(identifier.value);
return;
}
this.set(identifier.value,remain);
}
}
identifiers.addIdentifersByLine = function( editor, line ) {
var _identifiers = this.getIdentifiersByLine(editor,line);
_identifiers.forEach(this.addIdentifer.bind(this));
identifiersArray.splice(line,1,_identifiers);
}
identifiers.removeIdentifersByLine = function( editor, line ) {
var _identifiers = identifiersArray[line];
if(!_identifiers){
return;
}
_identifiers.forEach(this.removeIdentifier.bind(this));
identifiersArray.splice(line,1);
}
return {
has : function (name) {
return namespaces.indexOf(name) != -1;
},
getSource : function (name, token) {
console.log( name, token );
if( !this.has(name) ){
return [];
}
return filterSource(token, objlist[name]);
},
getGlobal : function ( token ) {
return filterSource(token, Gobj).concat(this.getIdentifier(token));
},
getIdentifier:function( token) {
return filterSource(token, identifiers.getNames())
},
identifiers: identifiers
};
})
define([
],function() {
function WeakMap () {
var names = [];
var map = {};
this.has = function (obj) {
var idx= names.indexOf(obj);
return idx !== -1;
}
this.get = function (obj) {
var idx = names.indexOf(obj);
if( idx != -1 ){
return map[idx];
}
}
this.set = function (obj, value) {
var idx = names.indexOf(obj)
if( idx != -1){
map[idx] = value;
} else {
map[names.push(obj)-1] = value;
}
}
this.remove = function (obj) {
var idx = names.indexOf(obj)
if( idx != -1){
delete names[idx];
map[idx] = undefined;
}
}
this.removeAll = function() {
names = [];
map = {};
}
this.getNames = function() {
return [].concat(names);
}
}
return WeakMap;
})
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment