From 1869964bfdcc7512596fbb7e23adfaf532a9de30 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BE=90=E5=BF=97=E6=AF=85?= Date: Tue, 2 Apr 2019 11:18:19 +0800 Subject: [PATCH] options command support complete options-name (#612) --- .../core/command/hidden/OptionsCommand.java | 69 ++++++++++++++----- .../command/klass100/SearchMethodCommand.java | 8 +-- .../taobao/arthas/core/util/TokenUtils.java | 29 ++++---- 3 files changed, 73 insertions(+), 33 deletions(-) diff --git a/core/src/main/java/com/taobao/arthas/core/command/hidden/OptionsCommand.java b/core/src/main/java/com/taobao/arthas/core/command/hidden/OptionsCommand.java index 6c5e6c70b..b316523e3 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/hidden/OptionsCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/hidden/OptionsCommand.java @@ -3,11 +3,15 @@ package com.taobao.arthas.core.command.hidden; import com.taobao.arthas.core.GlobalOptions; import com.taobao.arthas.core.Option; 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.StringUtils; +import com.taobao.arthas.core.util.TokenUtils; import com.taobao.arthas.core.util.matcher.EqualsMatcher; import com.taobao.arthas.core.util.matcher.Matcher; -import com.taobao.arthas.core.util.StringUtils; import com.taobao.arthas.core.util.matcher.RegexMatcher; import com.taobao.arthas.core.util.reflect.FieldUtils; import com.taobao.middleware.cli.annotations.Argument; @@ -22,6 +26,7 @@ import com.taobao.text.util.RenderUtil; import java.lang.reflect.Field; import java.util.ArrayList; import java.util.Collection; +import java.util.List; import static com.taobao.arthas.core.util.ArthasCheckUtils.isIn; import static com.taobao.text.ui.Element.label; @@ -69,18 +74,38 @@ public class OptionsCommand extends AnnotatedCommand { } } + /** + * complete first argument(options-name), other case use default complete + * + * @param completion the completion object + */ + @Override + public void complete(Completion completion) { + int argumentIndex = CompletionUtils.detectArgumentIndex(completion); + List lineTokens = completion.lineTokens(); + if (argumentIndex == 1) { + String laseToken = TokenUtils.getLast(lineTokens).value().trim(); + //prefix match options-name + String pattern = "^" + laseToken + ".*"; + Collection optionNames = findOptionNames(new RegexMatcher(pattern)); + CompletionUtils.complete(completion, optionNames); + } else { + super.complete(completion); + } + } + private void processShow(CommandProcess process) throws IllegalAccessException { - Collection fields = findOptions(new RegexMatcher(".*")); + Collection fields = findOptionFields(new RegexMatcher(".*")); process.write(RenderUtil.render(drawShowTable(fields), process.width())); } private void processShowName(CommandProcess process) throws IllegalAccessException { - Collection fields = findOptions(new EqualsMatcher(optionName)); + Collection fields = findOptionFields(new EqualsMatcher(optionName)); process.write(RenderUtil.render(drawShowTable(fields), process.width())); } private void processChangeNameValue(CommandProcess process) throws IllegalAccessException { - Collection fields = findOptions(new EqualsMatcher(optionName)); + Collection fields = findOptionFields(new EqualsMatcher(optionName)); // name not exists if (fields.isEmpty()) { @@ -132,7 +157,7 @@ public class OptionsCommand extends AnnotatedCommand { } - /* + /** * 判断当前动作是否需要展示整个options */ private boolean isShow() { @@ -140,30 +165,42 @@ public class OptionsCommand extends AnnotatedCommand { } - /* + /** * 判断当前动作是否需要展示某个Name的值 */ private boolean isShowName() { return !StringUtils.isBlank(optionName) && StringUtils.isBlank(optionValue); } - private Collection findOptions(Matcher optionNameMatcher) { + private Collection findOptionFields(Matcher optionNameMatcher) { final Collection matchFields = new ArrayList(); for (final Field optionField : FieldUtils.getAllFields(GlobalOptions.class)) { - if (!optionField.isAnnotationPresent(Option.class)) { - continue; + if (isMatchOptionAnnotation(optionField, optionNameMatcher)) { + matchFields.add(optionField); } - - final Option optionAnnotation = optionField.getAnnotation(Option.class); - if (optionAnnotation != null - && !optionNameMatcher.matching(optionAnnotation.name())) { - continue; - } - matchFields.add(optionField); } return matchFields; } + private Collection findOptionNames(Matcher optionNameMatcher) { + final Collection matchOptionNames = new ArrayList(); + for (final Field optionField : FieldUtils.getAllFields(GlobalOptions.class)) { + if (isMatchOptionAnnotation(optionField, optionNameMatcher)) { + final Option optionAnnotation = optionField.getAnnotation(Option.class); + matchOptionNames.add(optionAnnotation.name()); + } + } + return matchOptionNames; + } + + private boolean isMatchOptionAnnotation(Field optionField, Matcher optionNameMatcher) { + if (!optionField.isAnnotationPresent(Option.class)) { + return false; + } + final Option optionAnnotation = optionField.getAnnotation(Option.class); + return optionAnnotation != null && optionNameMatcher.matching(optionAnnotation.name()); + } + private Element drawShowTable(Collection optionFields) throws IllegalAccessException { TableElement table = new TableElement(1, 1, 2, 1, 3, 6) .leftCellPadding(1).rightCellPadding(1); diff --git a/core/src/main/java/com/taobao/arthas/core/command/klass100/SearchMethodCommand.java b/core/src/main/java/com/taobao/arthas/core/command/klass100/SearchMethodCommand.java index 110b9297c..7e22fc762 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/klass100/SearchMethodCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/klass100/SearchMethodCommand.java @@ -157,13 +157,13 @@ public class SearchMethodCommand extends AnnotatedCommand { public void complete(Completion completion) { int argumentIndex = CompletionUtils.detectArgumentIndex(completion); - if(argumentIndex == 1) { - if(!CompletionUtils.completeClassName(completion)) { + if (argumentIndex == 1) { + if (!CompletionUtils.completeClassName(completion)) { super.complete(completion); } return; - }else if(argumentIndex == 2) { - if(!CompletionUtils.completeMethodName(completion)) { + } else if (argumentIndex == 2) { + if (!CompletionUtils.completeMethodName(completion)) { super.complete(completion); } return; diff --git a/core/src/main/java/com/taobao/arthas/core/util/TokenUtils.java b/core/src/main/java/com/taobao/arthas/core/util/TokenUtils.java index b2cb89c3b..f3172d15b 100644 --- a/core/src/main/java/com/taobao/arthas/core/util/TokenUtils.java +++ b/core/src/main/java/com/taobao/arthas/core/util/TokenUtils.java @@ -1,27 +1,26 @@ package com.taobao.arthas.core.util; import java.util.List; + import com.taobao.arthas.core.shell.cli.CliToken; /** * tokenizer helper - * + * * @author gehui 2017-07-27 11:39:56 */ public class TokenUtils { /** * find the first text token - * @param tokens - * @return */ public static CliToken findFirstTextToken(List tokens) { - if(tokens==null || tokens.isEmpty()){ + if (tokens == null || tokens.isEmpty()) { return null; } CliToken first = null; for (CliToken token : tokens) { - if (token!=null && token.isText()) { + if (token != null && token.isText()) { first = token; break; } @@ -31,17 +30,15 @@ public class TokenUtils { /** * find the last text token - * @param tokens - * @return */ public static CliToken findLastTextToken(List tokens) { - if(tokens==null || tokens.isEmpty()){ + if (tokens == null || tokens.isEmpty()) { return null; } //#165 for (int i = tokens.size() - 1; i >= 0; i--) { CliToken token = tokens.get(i); - if (token!=null && token.isText()) { + if (token != null && token.isText()) { return token; } } @@ -50,16 +47,14 @@ public class TokenUtils { /** * find the second text token's text - * @param tokens - * @return */ public static String findSecondTokenText(List tokens) { - if(tokens==null || tokens.isEmpty()){ + if (tokens == null || tokens.isEmpty()) { return null; } boolean first = true; for (CliToken token : tokens) { - if (token!=null && token.isText()) { + if (token != null && token.isText()) { if (first) { first = false; } else { @@ -69,4 +64,12 @@ public class TokenUtils { } return null; } + + public static CliToken getLast(List tokens){ + if (tokens == null || tokens.isEmpty()) { + return null; + } else { + return tokens.get(tokens.size() -1); + } + } }