sm support completion. #323

This commit is contained in:
hengyunabc
2019-02-08 01:41:25 +08:00
parent 317e9d69ad
commit a2ef539f4e
2 changed files with 110 additions and 5 deletions
@@ -1,6 +1,9 @@
package com.taobao.arthas.core.command.klass100;
import com.taobao.arthas.core.command.Constants;
import com.taobao.arthas.core.shell.cli.CliToken;
import com.taobao.arthas.core.shell.cli.Completion;
import com.taobao.arthas.core.shell.cli.CompletionUtils;
import com.taobao.arthas.core.shell.command.AnnotatedCommand;
import com.taobao.arthas.core.shell.command.CommandProcess;
import com.taobao.arthas.core.util.matcher.Matcher;
@@ -23,6 +26,7 @@ import java.lang.instrument.Instrumentation;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import static com.taobao.text.Decoration.bold;
@@ -84,7 +88,7 @@ public class SearchMethodCommand extends AnnotatedCommand {
for (Class<?> clazz : matchedClasses) {
Set<String> methodNames = new HashSet<String>();
for (Constructor constructor : clazz.getDeclaredConstructors()) {
for (Constructor<?> constructor : clazz.getDeclaredConstructors()) {
if (!methodNameMatcher.matching("<init>")) {
continue;
}
@@ -146,7 +150,7 @@ public class SearchMethodCommand extends AnnotatedCommand {
return table;
}
private Element renderConstructor(Constructor constructor) {
private Element renderConstructor(Constructor<?> constructor) {
TableElement table = new TableElement().leftCellPadding(1).rightCellPadding(1);
table.row(label("declaring-class").style(bold.bold()), label(constructor.getDeclaringClass().getName()))
@@ -157,4 +161,23 @@ public class SearchMethodCommand extends AnnotatedCommand {
.row(label("exceptions").style(bold.bold()), label(TypeRenderUtils.drawExceptions(constructor)));
return table;
}
@Override
public void complete(Completion completion) {
int argumentIndex = CompletionUtils.detectArgumentIndex(completion);
if(argumentIndex == 1) {
if(!CompletionUtils.completeClassName(completion)) {
super.complete(completion);
}
return;
}else if(argumentIndex == 2) {
if(!CompletionUtils.completeMethodName(completion)) {
super.complete(completion);
}
return;
}
super.complete(completion);
}
}
@@ -2,6 +2,7 @@ package com.taobao.arthas.core.shell.cli;
import com.taobao.arthas.core.shell.session.Session;
import com.taobao.arthas.core.shell.term.Tty;
import com.taobao.arthas.core.util.SearchUtils;
import com.taobao.arthas.core.util.StringUtils;
import com.taobao.arthas.core.util.usage.StyledUsageFormatter;
import com.taobao.middleware.cli.CLI;
@@ -11,6 +12,7 @@ import io.termd.core.util.Helper;
import java.io.File;
import java.lang.instrument.Instrumentation;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
@@ -54,15 +56,20 @@ public class CompletionUtils {
*/
public static boolean complete(Completion completion, Collection<String> searchScope) {
List<CliToken> tokens = completion.lineTokens();
CliToken lastToken = tokens.get(tokens.size() - 1);
String lastToken = tokens.get(tokens.size() - 1).value();
List<String> candidates = new ArrayList<String>();
if (StringUtils.isBlank(lastToken)) {
lastToken = "";
}
for (String name: searchScope) {
if (" ".equals(lastToken.value()) || name.startsWith(lastToken.value())) {
if (name.startsWith(lastToken)) {
candidates.add(name);
}
}
if (candidates.size() == 1) {
completion.complete(candidates.get(0).substring(lastToken.value().length()), true);
completion.complete(candidates.get(0).substring(lastToken.length()), true);
return true;
} else {
completion.complete(candidates);
@@ -182,6 +189,81 @@ public class CompletionUtils {
return true;
}
public static boolean completeMethodName(Completion completion) {
List<CliToken> tokens = completion.lineTokens();
String lastToken = completion.lineTokens().get(tokens.size() - 1).value();
// retrieve the class name
String className;
if (StringUtils.isBlank(lastToken)) {
// tokens = { " ", "CLASS_NAME", " "}
className = tokens.get(tokens.size() - 2).value();
} else {
// tokens = { " ", "CLASS_NAME", " ", "PARTIAL_METHOD_NAME"}
className = tokens.get(tokens.size() - 3).value();
}
Set<Class<?>> results = SearchUtils.searchClassOnly(completion.session().getInstrumentation(), className, 2);
if (results.isEmpty() || results.size() > 1) {
// no class found or multiple class found
completion.complete(Collections.<String>emptyList());
return true;
}
Class<?> clazz = results.iterator().next();
List<String> res = new ArrayList<String>();
for (Method method : clazz.getDeclaredMethods()) {
if (StringUtils.isBlank(lastToken)) {
res.add(method.getName());
} else if (method.getName().startsWith(lastToken)) {
res.add(method.getName());
}
}
if (res.size() == 1) {
completion.complete(res.get(0).substring(lastToken.length()), true);
return true;
} else {
CompletionUtils.complete(completion, res);
return true;
}
}
/**
* 推断输入到哪一个 argument
* @param completion
* @return
*/
public static int detectArgumentIndex(Completion completion) {
List<CliToken> tokens = completion.lineTokens();
CliToken lastToken = tokens.get(tokens.size() - 1);
if (lastToken.value().startsWith("-") || lastToken.value().startsWith("--")) {
return -1;
}
if (StringUtils.isBlank((lastToken.value())) && tokens.size() == 1) {
return 1;
}
int tokenCount = 0;
for (CliToken token : tokens) {
if (StringUtils.isBlank(token.value()) || token.value().startsWith("-") || token.value().startsWith("--")) {
// filter irrelevant tokens
continue;
}
tokenCount++;
}
if (StringUtils.isBlank((lastToken.value())) && tokens.size() != 1) {
tokenCount++;
}
return tokenCount;
}
public static void completeShortOption(Completion completion, CliToken lastToken, List<Option> options) {
String prefix = lastToken.value().substring(1);
List<String> candidates = new ArrayList<String>();