You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@karaf.apache.org by gn...@apache.org on 2016/07/20 10:59:39 UTC
karaf git commit: [KARAF-4554] Completion of the 'watch' command
hangs Karaf
Repository: karaf
Updated Branches:
refs/heads/master d14ac13b3 -> a26dea75e
[KARAF-4554] Completion of the 'watch' command hangs Karaf
Project: http://git-wip-us.apache.org/repos/asf/karaf/repo
Commit: http://git-wip-us.apache.org/repos/asf/karaf/commit/a26dea75
Tree: http://git-wip-us.apache.org/repos/asf/karaf/tree/a26dea75
Diff: http://git-wip-us.apache.org/repos/asf/karaf/diff/a26dea75
Branch: refs/heads/master
Commit: a26dea75e03108439334e853d0d86333576560f0
Parents: d14ac13
Author: Guillaume Nodet <gn...@apache.org>
Authored: Wed Jul 20 12:59:25 2016 +0200
Committer: Guillaume Nodet <gn...@apache.org>
Committed: Wed Jul 20 12:59:25 2016 +0200
----------------------------------------------------------------------
.../karaf/shell/commands/impl/WatchAction.java | 109 +++++++++++++++--
.../shell/impl/console/CommandsCompleter.java | 2 +-
.../shell/impl/console/ConsoleSessionImpl.java | 3 +-
.../shell/impl/console/parsing/KarafParser.java | 117 +++++++++++++++++++
4 files changed, 220 insertions(+), 11 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/karaf/blob/a26dea75/shell/commands/src/main/java/org/apache/karaf/shell/commands/impl/WatchAction.java
----------------------------------------------------------------------
diff --git a/shell/commands/src/main/java/org/apache/karaf/shell/commands/impl/WatchAction.java b/shell/commands/src/main/java/org/apache/karaf/shell/commands/impl/WatchAction.java
index 9e25585..7f46282 100644
--- a/shell/commands/src/main/java/org/apache/karaf/shell/commands/impl/WatchAction.java
+++ b/shell/commands/src/main/java/org/apache/karaf/shell/commands/impl/WatchAction.java
@@ -21,6 +21,8 @@ package org.apache.karaf.shell.commands.impl;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.PrintStream;
+import java.util.ArrayList;
+import java.util.List;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
@@ -30,14 +32,22 @@ import org.apache.karaf.shell.api.action.Argument;
import org.apache.karaf.shell.api.action.Command;
import org.apache.karaf.shell.api.action.Completion;
import org.apache.karaf.shell.api.action.Option;
+import org.apache.karaf.shell.api.action.Parsing;
import org.apache.karaf.shell.api.action.lifecycle.Reference;
import org.apache.karaf.shell.api.action.lifecycle.Service;
+import org.apache.karaf.shell.api.console.CommandLine;
+import org.apache.karaf.shell.api.console.Completer;
+import org.apache.karaf.shell.api.console.Parser;
import org.apache.karaf.shell.api.console.Session;
import org.apache.karaf.shell.api.console.SessionFactory;
+import org.apache.karaf.shell.commands.impl.WatchAction.WatchParser;
import org.apache.karaf.shell.support.ShellUtil;
import org.apache.karaf.shell.support.completers.CommandsCompleter;
+import org.apache.karaf.shell.support.parsing.CommandLineImpl;
+import org.apache.karaf.shell.support.parsing.DefaultParser;
@Command(scope = "shell", name = "watch", description = "Watches & refreshes the output of a command")
+@Parsing(WatchParser.class)
@Service
public class WatchAction implements Action {
@@ -47,9 +57,9 @@ public class WatchAction implements Action {
@Option(name = "-a", aliases = {"--append"}, description = "The output should be appended but not clear the console", required = false, multiValued = false)
private boolean append = false;
- @Argument(index = 0, name = "command", description = "The command to watch / refresh", required = true, multiValued = true)
- @Completion(CommandsCompleter.class)
- private String[] arguments;
+ @Argument(index = 0, name = "command", description = "The command to watch / refresh", required = true, multiValued = false)
+ @Completion(SubCommandCompleter.class)
+ private String arguments;
@Reference
Session session;
@@ -61,14 +71,10 @@ public class WatchAction implements Action {
@Override
public Object execute() throws Exception {
- if (arguments == null || arguments.length == 0) {
+ if (arguments == null || arguments.length() == 0) {
System.err.println("Argument expected");
} else {
- StringBuilder command = new StringBuilder();
- for (String arg : arguments) {
- command.append(arg).append(" ");
- }
- WatchTask watchTask = new WatchTask(command.toString().trim());
+ WatchTask watchTask = new WatchTask(arguments.trim());
executorService.scheduleAtFixedRate(watchTask, 0, interval, TimeUnit.SECONDS);
try {
session.getKeyboard().read();
@@ -137,4 +143,89 @@ public class WatchAction implements Action {
}
}
+ @Service
+ public static class WatchParser implements Parser {
+ @Override
+ public CommandLine parse(Session session, String command, int cursor) {
+ int n1 = 0;
+ while (n1 < command.length() && Character.isWhitespace(command.charAt(n1))) {
+ n1++;
+ if (n1 == command.length()) {
+ throw new IllegalArgumentException();
+ }
+ }
+ int n2 = n1 + 1;
+ while (!Character.isWhitespace(command.charAt(n2))) {
+ n2++;
+ if (n2 == command.length()) {
+ return new CommandLineImpl(
+ new String[]{command.substring(n1)},
+ 0,
+ cursor - n1,
+ cursor,
+ command
+ );
+ }
+ }
+ int n3 = n2 + 1;
+ while (n3 < command.length() && Character.isWhitespace(command.charAt(n3))) {
+ n3++;
+ if (n3 == command.length()) {
+ return new CommandLineImpl(
+ new String[]{command.substring(n1, n2), ""},
+ cursor >= n2 ? 1 : 0,
+ cursor >= n2 ? 0 : cursor - n1,
+ cursor,
+ command
+ );
+ }
+ }
+ return new CommandLineImpl(
+ new String[]{command.substring(n1, n2), command.substring(n3)},
+ cursor >= n3 ? 1 : 0,
+ cursor >= n3 ? cursor - n3 : cursor - n1,
+ cursor,
+ command
+ );
+ }
+
+ @Override
+ public String preprocess(Session session, CommandLine cmdLine) {
+ StringBuilder parsed = new StringBuilder();
+ for (int i = 0; i < cmdLine.getArguments().length; i++) {
+ String arg = cmdLine.getArguments()[i];
+ if (i > 0) {
+ parsed.append(" \"");
+ }
+ parsed.append(arg);
+ if (i > 0) {
+ parsed.append("\"");
+ }
+ }
+ return parsed.toString();
+ }
+ }
+
+ @Service
+ public static class SubCommandCompleter implements Completer {
+
+ @Override
+ public int complete(Session session, CommandLine commandLine, List<String> candidates) {
+ String arg = commandLine.getCursorArgument();
+ int pos = commandLine.getArgumentPosition();
+ CommandLine cmdLine = new DefaultParser().parse(session, arg, pos);
+ Completer completer = session.getRegistry().getService(CommandsCompleter.class);
+ List<String> cands = new ArrayList<>();
+ int res = completer.complete(session, cmdLine, cands);
+ for (String cand : cands) {
+ candidates.add(arg.substring(0, cmdLine.getBufferPosition() - cmdLine.getArgumentPosition()) + cand);
+ }
+ if (res >= 0) {
+ res += commandLine.getBufferPosition() - commandLine.getArgumentPosition();
+ }
+ return res;
+ }
+
+ }
+
}
http://git-wip-us.apache.org/repos/asf/karaf/blob/a26dea75/shell/core/src/main/java/org/apache/karaf/shell/impl/console/CommandsCompleter.java
----------------------------------------------------------------------
diff --git a/shell/core/src/main/java/org/apache/karaf/shell/impl/console/CommandsCompleter.java b/shell/core/src/main/java/org/apache/karaf/shell/impl/console/CommandsCompleter.java
index 8a878d3..84f87c6 100644
--- a/shell/core/src/main/java/org/apache/karaf/shell/impl/console/CommandsCompleter.java
+++ b/shell/core/src/main/java/org/apache/karaf/shell/impl/console/CommandsCompleter.java
@@ -44,7 +44,7 @@ import org.jline.reader.ParsedLine;
/**
* Overall command line completer.
*/
-public class CommandsCompleter implements org.jline.reader.Completer {
+public class CommandsCompleter extends org.apache.karaf.shell.support.completers.CommandsCompleter implements org.jline.reader.Completer {
private final SessionFactory factory;
private final Session session;
http://git-wip-us.apache.org/repos/asf/karaf/blob/a26dea75/shell/core/src/main/java/org/apache/karaf/shell/impl/console/ConsoleSessionImpl.java
----------------------------------------------------------------------
diff --git a/shell/core/src/main/java/org/apache/karaf/shell/impl/console/ConsoleSessionImpl.java b/shell/core/src/main/java/org/apache/karaf/shell/impl/console/ConsoleSessionImpl.java
index 413f2af..d338f47 100644
--- a/shell/core/src/main/java/org/apache/karaf/shell/impl/console/ConsoleSessionImpl.java
+++ b/shell/core/src/main/java/org/apache/karaf/shell/impl/console/ConsoleSessionImpl.java
@@ -44,6 +44,7 @@ import org.apache.karaf.shell.api.console.Session;
import org.apache.karaf.shell.api.console.SessionFactory;
import org.apache.karaf.shell.api.console.Terminal;
import org.apache.karaf.shell.impl.console.parsing.CommandLineParser;
+import org.apache.karaf.shell.impl.console.parsing.KarafParser;
import org.apache.karaf.shell.support.ShellUtil;
import org.apache.karaf.shell.support.completers.FileCompleter;
import org.apache.karaf.shell.support.completers.FileOrUriCompleter;
@@ -187,7 +188,7 @@ public class ConsoleSessionImpl implements Session {
session.currentDir(null);
reader.setHighlighter(new org.apache.felix.gogo.jline.Highlighter(session));
- reader.setParser(new org.apache.felix.gogo.jline.Parser());
+ reader.setParser(new KarafParser(this));
}
http://git-wip-us.apache.org/repos/asf/karaf/blob/a26dea75/shell/core/src/main/java/org/apache/karaf/shell/impl/console/parsing/KarafParser.java
----------------------------------------------------------------------
diff --git a/shell/core/src/main/java/org/apache/karaf/shell/impl/console/parsing/KarafParser.java b/shell/core/src/main/java/org/apache/karaf/shell/impl/console/parsing/KarafParser.java
new file mode 100644
index 0000000..334e960
--- /dev/null
+++ b/shell/core/src/main/java/org/apache/karaf/shell/impl/console/parsing/KarafParser.java
@@ -0,0 +1,117 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.karaf.shell.impl.console.parsing;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+import org.apache.felix.gogo.jline.ParsedLineImpl;
+import org.apache.felix.gogo.runtime.EOFError;
+import org.apache.felix.gogo.runtime.Parser.Program;
+import org.apache.felix.gogo.runtime.Parser.Statement;
+import org.apache.felix.gogo.runtime.SyntaxError;
+import org.apache.felix.gogo.runtime.Token;
+import org.apache.karaf.shell.api.console.Command;
+import org.apache.karaf.shell.api.console.CommandLine;
+import org.apache.karaf.shell.api.console.Parser;
+import org.apache.karaf.shell.api.console.Session;
+import org.apache.karaf.shell.support.parsing.DefaultParser;
+import org.jline.reader.ParsedLine;
+
+public class KarafParser implements org.jline.reader.Parser {
+
+ private final Session session;
+
+ public KarafParser(Session session) {
+ this.session = session;
+ }
+
+ public ParsedLine parse(String line, int cursor) throws org.jline.reader.SyntaxError {
+ try {
+ return doParse(line, cursor);
+ } catch (EOFError e) {
+ throw new org.jline.reader.EOFError(e.line(), e.column(), e.getMessage(), e.missing());
+ } catch (SyntaxError e) {
+ throw new org.jline.reader.SyntaxError(e.line(), e.column(), e.getMessage());
+ }
+ }
+
+ private ParsedLine doParse(CharSequence line, int cursor) throws SyntaxError {
+ org.apache.felix.gogo.runtime.Parser parser = new org.apache.felix.gogo.runtime.Parser(line);
+ Program program = parser.program();
+ List<Statement> statements = parser.statements();
+ // Find corresponding statement
+ Statement statement = null;
+ for (int i = statements.size() - 1; i >= 0; i--) {
+ Statement s = statements.get(i);
+ if (s.start() <= cursor) {
+ boolean isOk = true;
+ // check if there are only spaces after the previous statement
+ if (s.start() + s.length() < cursor) {
+ for (int j = s.start() + s.length(); isOk && j < cursor; j++) {
+ isOk = Character.isWhitespace(line.charAt(j));
+ }
+ }
+ statement = s;
+ break;
+ }
+ }
+ if (statement != null) {
+ String cmdName = session.resolveCommand(statement.tokens().get(0).toString());
+ String[] parts = cmdName.split(":");
+ Command cmd = parts.length == 2 ? session.getRegistry().getCommand(parts[0], parts[1]) : null;
+ Parser cmdParser = cmd != null ? cmd.getParser() : null;
+ if (cmdParser != null) {
+ final CommandLine cmdLine = cmdParser.parse(session, statement.toString(), cursor - statement.start());
+ return new ParsedLine() {
+ @Override
+ public String word() {
+ return cmdLine.getCursorArgument();
+ }
+ @Override
+ public int wordCursor() {
+ return cmdLine.getArgumentPosition();
+ }
+ @Override
+ public int wordIndex() {
+ return cmdLine.getCursorArgumentIndex();
+ }
+ @Override
+ public List<String> words() {
+ return Arrays.asList(cmdLine.getArguments());
+ }
+ @Override
+ public String line() {
+ return cmdLine.getBuffer();
+ }
+ @Override
+ public int cursor() {
+ return cmdLine.getBufferPosition();
+ }
+ };
+ }
+ return new ParsedLineImpl(program, statement, cursor, statement.tokens());
+ } else {
+ // TODO:
+ return new ParsedLineImpl(program, program, cursor, Collections.<Token>singletonList(program));
+ }
+ }
+
+}