This repository has been archived on 2021-07-14. You can view files and clone it, but cannot push or open issues or pull requests.
scriptcraft/src/main/js/lib/tabcomplete.js
walterhiggins 19162c3688 First phase of transition from Bukkit to Canary.
Some of the plugins are not yet supported.
If you're feeling brave you can build from source using ant.
2014-09-29 23:42:41 +01:00

256 lines
6.7 KiB
JavaScript

'use strict';
var tabCompleteJSP = require('tabcomplete-jsp'),
isJavaObject = require('java-utils').isJavaObject;
/*
Tab Completion of the /js and /jsp commands
*/
var _javaLangObjectMethods = [
'equals'
,'getClass'
,'class'
,'getClass'
,'hashCode'
,'notify'
,'notifyAll'
,'toString'
,'wait'
,'clone'
,'finalize'
];
var _getProperties = function( o ) {
var result = [],
i,
j,
isObjectMethod,
propValue,
typeofProperty;
if ( isJavaObject( o ) ) {
/*
fix for issue #115 - java objects are not iterable
see: http://mail.openjdk.java.net/pipermail/nashorn-dev/2014-March/002790.html
*/
if ( typeof Object.bindProperties === 'function' ) {
var placeholder = {};
Object.bindProperties(placeholder, o);
o = placeholder;
}
propertyLoop:
for ( i in o ) {
//
// don't include standard Object methods
//
isObjectMethod = false;
for ( j = 0; j < _javaLangObjectMethods.length; j++ ) {
if ( _javaLangObjectMethods[j] == i ) {
continue propertyLoop;
}
}
typeofProperty = null;
try {
propValue = o[i];
typeofProperty = typeof propValue;
} catch( e ) {
if ( e.message == 'java.lang.IllegalStateException: Entity not leashed' ) {
// wph 20131020 fail silently for Entity leashing in craftbukkit
} else {
// don't throw an error during tab completion just make a best effort to
// do the job.
}
}
if ( typeofProperty == 'function' ) {
result.push( i+'()' );
} else {
result.push( i );
}
}
} else {
if ( o.constructor == Array ) {
return result;
}
for ( i in o ) {
if ( i.match( /^[^_]/ ) ) {
if ( typeof o[i] == 'function'){
if ( ! (o[i] instanceof java.lang.Object) ) {
try {
if (o[i].constructor){} // throws error for java objects in jre7
result.push(i + '()');
} catch (e ){
result.push(i);
}
}else {
result.push( i );
}
} else {
result.push( i );
}
}
}
}
return result.sort();
};
var onTabCompleteJS = function( ) {
var _globalSymbols,
lastArg,
propsOfLastArg,
statement,
statementSyms,
lastSymbol,
parts,
name,
symbol,
lastGoodSymbol,
lastArgProp,
i,
objectProps,
candidate,
re,
li,
possibleCompletion,
result,
cmdSender,
pluginCmd,
cmdArgs;
result = arguments[0];
cmdSender = arguments[1];
if (__plugin.bukkit){
pluginCmd = arguments[2].name;
cmdArgs = arguments[4];
}
if (__plugin.canary){
cmdArgs = arguments[2];
pluginCmd = arguments[3];
}
cmdArgs = Array.prototype.slice.call( cmdArgs, 0 );
if (__plugin.canary){
// if 1st element is 'js' then splice
// there's probably a better way to do this
if (cmdArgs[0] == 'js'){
cmdArgs = cmdArgs.slice(1);
}
}
if ( pluginCmd == 'jsp' ) {
return tabCompleteJSP( result, cmdArgs );
}
global.self = cmdSender; // bring in self just for autocomplete
_globalSymbols = _getProperties(global);
lastArg = cmdArgs.length ? cmdArgs[ cmdArgs.length - 1 ] + '' : null;
propsOfLastArg = [];
statement = cmdArgs.join(' ');
statement = statement.replace(/^\s+/,'').replace(/\s+$/,'');
if ( statement.length == 0 ) {
propsOfLastArg = _globalSymbols;
} else {
if (statement.match(/\)$/)){
return;
}
statementSyms = statement.split(/[^\$a-zA-Z0-9_\.]/);
lastSymbol = statementSyms[statementSyms.length-1];
//print('DEBUG: lastSymbol=[' + lastSymbol + ']');
//
// try to complete the object ala java IDEs.
//
parts = lastSymbol.split(/\./);
name = parts[0];
symbol = global[name];
//print('DEBUG: name=' + name + ',symbol=' + symbol);
lastGoodSymbol = symbol;
if ( typeof symbol !== 'undefined' ) {
for ( i = 1; i < parts.length; i++ ) {
name = parts[i];
if ( !name ) { // fix issue #115
break;
}
try {
// this causes problems in jre if symbol is an enum and name is partial-match
symbol = symbol[name]; // this causes problem in jre8 if name is ''
} catch (e){
symbol = null;
break;
}
if ( typeof symbol == 'undefined' ) {
break;
}
// nashorn - object[missingProperty] returns null not undefined
if ( symbol == null ) {
break;
}
lastGoodSymbol = symbol;
}
if ( typeof symbol == 'undefined' || symbol === null) {
//
// look up partial matches against last good symbol
//
objectProps = _getProperties( lastGoodSymbol );
if ( name == '' ) {
// if the last symbol looks like this..
// server.
//
//print('debug:case Y1: server.');
for ( i = 0; i < objectProps.length; i++ ) {
candidate = lastSymbol + objectProps[i];
re = new RegExp( lastSymbol + '$', 'g' );
propsOfLastArg.push( lastArg.replace( re, candidate ) );
}
} else {
// it looks like this..
// server.wo
//
//print('debug:case Y2: server.wo');
li = statement.lastIndexOf(name);
for ( i = 0; i < objectProps.length; i++ ) {
if ( objectProps[i].indexOf(name) == 0 ) {
candidate = lastSymbol.substring( 0, lastSymbol.lastIndexOf( name ) );
candidate = candidate + objectProps[i];
re = new RegExp( lastSymbol + '$', 'g' );
propsOfLastArg.push( lastArg.replace( re, candidate ) );
}
}
}
} else {
//print('debug:case Y3: server');
objectProps = _getProperties( symbol );
for ( i = 0; i < objectProps.length; i++ ) {
re = new RegExp( lastSymbol+ '$', 'g' );
lastArgProp = lastArg.replace( re, lastSymbol + '.' + objectProps[i] ) ;
lastArgProp = lastArgProp.replace(/\.\./g,'.');
propsOfLastArg.push( lastArgProp );
}
}
} else {
for ( i = 0; i < _globalSymbols.length; i++ ) {
if ( _globalSymbols[i].indexOf(lastSymbol) == 0 ) {
possibleCompletion = _globalSymbols[i];
re = new RegExp( lastSymbol+ '$', 'g' );
propsOfLastArg.push( lastArg.replace( re, possibleCompletion ) );
}
}
}
}
for ( i = 0; i < propsOfLastArg.length; i++ ) {
result.add( propsOfLastArg[i] );
}
delete global.self; // delete self when no longer needed for autocomplete
};
module.exports = onTabCompleteJS;