public List<String> onTabComplete( CommandSender commandSender, Command command, String s, String[] strings) { for (TabCompleter completer : delegateCompleters) { List<String> list = completer.onTabComplete(commandSender, command, s, strings); if (list != null) return list; } String expression = strings[strings.length - 1]; TreeSet<String> result = new TreeSet<String>(); Caller caller = plugin.getCallerService().getCaller(commandSender); WorkspaceService service = plugin.getWorkspaceService(); String workspaceName = service.getWorkspaceName(commandSender); Workspace workspace = service.getWorkspace(workspaceName); LinkedList<String> tokens = new LinkedList<String>(); boolean needHelp = expression.endsWith("?"); if (needHelp) expression = expression.substring(0, expression.length() - 1); Collections.addAll(tokens, expression.split("\\.")); if (expression.endsWith(".")) tokens.add(""); if (needHelp) { getHelp(caller, workspace, tokens); return Collections.singletonList(expression); } String firstToken = tokens.pollFirst(); if (firstToken == null) firstToken = ""; MetaClass callerScriptMetaClass = InvokerHelper.getMetaClass(CallerScript.class); MetaClass workspaceMetaClass = InvokerHelper.getMetaClass(Workspace.class); Map workspaceVars = null; if (workspace != null) workspaceVars = workspace.getBinding().getVariables(); Map globalVars = service.getBinding().getVariables(); PreparedScriptProperties properties = new PreparedScriptProperties(); properties.setCaller(caller); properties.setServer(plugin.getServer()); properties.setWorkspace(workspace); if (tokens.isEmpty()) { // get current method or class for (MetaProperty metaProperty : callerScriptMetaClass.getProperties()) { String name = metaProperty.getName(); if (name.contains(firstToken)) result.add(name); } for (String name : service.getImportTabCompleteClasses().keySet()) { if (name.contains(firstToken)) result.add(name); } for (MetaMethod metaMethod : callerScriptMetaClass.getMetaMethods()) { if (metaMethod.getDeclaringClass().getTheClass().equals(Object.class)) continue; String name = metaMethod.getName(); if (name.contains(firstToken)) { String methodEnd = "("; if (metaMethod.isValidMethod(new Class[] {Closure.class})) methodEnd = "{"; else if (metaMethod.getParameterTypes().length == 0) methodEnd = "()"; result.add(name + methodEnd); } int args = metaMethod.getParameterTypes().length; if ((name.startsWith("get") && args == 0 || name.startsWith("set") && args == 1) && name.length() > 3) { String propertyName = getPropertyName(name); if (propertyName != null && propertyName.contains(firstToken)) result.add(propertyName); } } for (MetaMethod metaMethod : workspaceMetaClass.getMetaMethods()) { if (metaMethod.getDeclaringClass().getTheClass().equals(Object.class)) continue; String name = metaMethod.getName(); if (name.contains(firstToken)) { String methodEnd = "("; if (metaMethod.isValidMethod(new Class[] {Closure.class})) methodEnd = "{"; else if (metaMethod.getParameterTypes().length == 0) methodEnd = "()"; result.add(name + methodEnd); } } for (Method method : CallerScript.class.getMethods()) { if (method.getDeclaringClass().equals(Object.class)) continue; String name = method.getName(); if (name.contains(firstToken)) { String methodEnd = "("; Class<?>[] types = method.getParameterTypes(); if (types.length == 1 && Closure.class.isAssignableFrom(types[0])) methodEnd = "{"; else if (types.length == 0) methodEnd = "()"; result.add(name + methodEnd); int args = method.getParameterTypes().length; if ((name.startsWith("get") && args == 0 || name.startsWith("set") && args == 1) && name.length() > 3) { String propertyName = getPropertyName(name); if (propertyName != null && propertyName.contains(firstToken)) result.add(propertyName); } } } for (Method method : Workspace.class.getMethods()) { if (method.getDeclaringClass().equals(Object.class)) continue; String name = method.getName(); if (name.contains(firstToken)) { String methodEnd = "("; Class<?>[] types = method.getParameterTypes(); if (types.length == 1 && Closure.class.isAssignableFrom(types[0])) methodEnd = "{"; else if (types.length == 0) methodEnd = "()"; result.add(name + methodEnd); } } if (workspaceVars != null) for (Object key : workspaceVars.keySet()) { String name = key.toString(); if (name.contains(firstToken)) result.add(name); } if (globalVars != null) for (Object key : globalVars.keySet()) { String name = key.toString(); if (name.contains(firstToken)) result.add(name); } for (GroovyObject modifier : CallerScript.getDynamicModifiers()) { Object[] params = {properties}; try { Map<?, ?> map = (Map) modifier.getMetaClass().invokeMethod(modifier, "getPropertyMapFor", params); for (Object key : map.keySet()) { String name = key.toString(); if (name.contains(firstToken)) result.add(name); } } catch (Exception ignored) { } try { Map<?, ?> map = (Map) modifier.getMetaClass().invokeMethod(modifier, "getMethodMapFor", params); for (Object key : map.keySet()) { String name = key.toString(); if (name.contains(firstToken)) result.add(name + "("); } } catch (Exception ignored) { } } if (globalVars != null) for (Object key : globalVars.keySet()) { String name = key.toString(); if (name.contains(firstToken)) result.add(name); } return new ArrayList<String>(result); } // get metaclass of first token MetaClass metaClass = getFirstTokenMeta( caller, firstToken, commandSender, service, callerScriptMetaClass, workspaceMetaClass, workspace, workspaceVars, globalVars, properties); boolean classHook = tokens.size() <= 1 && service.getImportTabCompleteClasses().containsKey(firstToken); if (metaClass == null) return null; metaClass = skipTokens(tokens, metaClass); if (metaClass == null) return null; // select property or method of last metaclass String token = tokens.pollFirst(); Class theClass = metaClass.getTheClass(); String inputPrefix = expression.substring(0, expression.lastIndexOf('.')) + "."; for (MetaProperty metaProperty : metaClass.getProperties()) { String name = metaProperty.getName(); if (name.startsWith(token)) result.add(inputPrefix + name); } for (MetaMethod metaMethod : metaClass.getMetaMethods()) { if (metaMethod.getDeclaringClass().getTheClass().equals(Object.class)) continue; String name = metaMethod.getName(); if (name.startsWith(token)) { String methodEnd = "("; if (metaMethod.isValidMethod(new Class[] {Closure.class})) methodEnd = "{"; else if (metaMethod.getNativeParameterTypes().length == 0) methodEnd = "()"; result.add(inputPrefix + name + methodEnd); } int args = metaMethod.getParameterTypes().length; if ((name.startsWith("get") && args == 0 || name.startsWith("set") && args == 1) && name.length() > 3) { String propertyName = getPropertyName(name); if (propertyName != null && propertyName.startsWith(token)) result.add(inputPrefix + propertyName); } } for (Method method : theClass.getMethods()) { if (method.getDeclaringClass().equals(Object.class)) continue; String name = method.getName(); if (name.startsWith(token)) { String methodEnd = "("; Class<?>[] types = method.getParameterTypes(); if (types.length == 1 && Closure.class.isAssignableFrom(types[0])) methodEnd = "{"; if (types.length == 0) methodEnd = "()"; result.add(inputPrefix + name + methodEnd); } int args = method.getParameterTypes().length; if ((name.startsWith("get") && args == 0 || name.startsWith("set") && args == 1) && name.length() > 3) { String propertyName = getPropertyName(name); if (propertyName != null && propertyName.startsWith(token)) result.add(inputPrefix + propertyName); } } if (Enum.class.isAssignableFrom(theClass)) { Enum[] enumValues = getEnumValues(theClass); if (enumValues != null) for (Enum anEnum : enumValues) { String name = anEnum.name(); if (name.startsWith(token)) result.add(inputPrefix + name); } } if (classHook) { for (MetaProperty metaProperty : InvokerHelper.getMetaClass(Class.class).getProperties()) { String name = metaProperty.getName(); if (name.startsWith(token)) result.add(inputPrefix + name); } for (Method method : Class.class.getMethods()) { if (method.getDeclaringClass().equals(Object.class)) continue; String name = method.getName(); if (name.startsWith(token)) { String methodEnd = "("; Class<?>[] types = method.getParameterTypes(); if (types.length == 1 && Closure.class.isAssignableFrom(types[0])) methodEnd = "{"; if (types.length == 0) methodEnd = "()"; result.add(inputPrefix + name + methodEnd); } int args = method.getParameterTypes().length; if ((name.startsWith("get") && args == 0 || name.startsWith("set") && args == 1) && name.length() > 3) { String propertyName = getPropertyName(name); if (propertyName != null && propertyName.startsWith(token)) result.add(inputPrefix + propertyName); } } } return new ArrayList<String>(result); }
private void createMetaMethodFromClass(Map<CachedClass, List<MetaMethod>> map, Class aClass) { try { MetaMethod method = (MetaMethod) aClass.newInstance(); final CachedClass declClass = method.getDeclaringClass(); List<MetaMethod> arr = map.get(declClass); if (arr == null) { arr = new ArrayList<MetaMethod>(4); map.put(declClass, arr); } arr.add(method); instanceMethods.add(method); } catch (InstantiationException e) { /* ignore */ } catch (IllegalAccessException e) { /* ignore */ } }
private void registerMethods( final Class theClass, final boolean useMethodWrapper, final boolean useInstanceMethods, Map<CachedClass, List<MetaMethod>> map) { if (useMethodWrapper) { // Here we instantiate objects representing MetaMethods for DGM methods. // Calls for such meta methods done without reflection, so more effectively. try { List<GeneratedMetaMethod.DgmMethodRecord> records = GeneratedMetaMethod.DgmMethodRecord.loadDgmInfo(); for (GeneratedMetaMethod.DgmMethodRecord record : records) { Class[] newParams = new Class[record.parameters.length - 1]; System.arraycopy(record.parameters, 1, newParams, 0, record.parameters.length - 1); MetaMethod method = new GeneratedMetaMethod.Proxy( record.className, record.methodName, ReflectionCache.getCachedClass(record.parameters[0]), record.returnType, newParams); final CachedClass declClass = method.getDeclaringClass(); List<MetaMethod> arr = map.get(declClass); if (arr == null) { arr = new ArrayList<MetaMethod>(4); map.put(declClass, arr); } arr.add(method); instanceMethods.add(method); } } catch (Throwable e) { e.printStackTrace(); // we print the error, but we don't stop with an exception here // since it is more comfortable this way for development } } else { CachedMethod[] methods = ReflectionCache.getCachedClass(theClass).getMethods(); for (CachedMethod method : methods) { final int mod = method.getModifiers(); if (Modifier.isStatic(mod) && Modifier.isPublic(mod) && method.getCachedMethod().getAnnotation(Deprecated.class) == null) { CachedClass[] paramTypes = method.getParameterTypes(); if (paramTypes.length > 0) { List<MetaMethod> arr = map.get(paramTypes[0]); if (arr == null) { arr = new ArrayList<MetaMethod>(4); map.put(paramTypes[0], arr); } if (useInstanceMethods) { final NewInstanceMetaMethod metaMethod = new NewInstanceMetaMethod(method); arr.add(metaMethod); instanceMethods.add(metaMethod); } else { final NewStaticMetaMethod metaMethod = new NewStaticMetaMethod(method); arr.add(metaMethod); staticMethods.add(metaMethod); } } } } } }