Author: gnodet
Date: Mon Mar 21 16:54:22 2016
New Revision: 1736006

URL: http://svn.apache.org/viewvc?rev=1736006&view=rev
Log:
Clean up a bit

Removed:
    
felix/trunk/gogo/jline/src/main/java/org/apache/felix/gogo/jline/IoUtils.java
    
felix/trunk/gogo/jline/src/main/java/org/apache/felix/gogo/jline/JLineCommands.java
    
felix/trunk/gogo/jline/src/main/java/org/apache/felix/gogo/jline/JLineCompletionEnvironment.java
Modified:
    
felix/trunk/gogo/jline/src/main/java/org/apache/felix/gogo/jline/Activator.java
    
felix/trunk/gogo/jline/src/main/java/org/apache/felix/gogo/jline/Builtin.java
    
felix/trunk/gogo/jline/src/main/java/org/apache/felix/gogo/jline/Highlighter.java
    felix/trunk/gogo/jline/src/main/java/org/apache/felix/gogo/jline/Main.java
    
felix/trunk/gogo/jline/src/main/java/org/apache/felix/gogo/jline/ParsedLineImpl.java
    felix/trunk/gogo/jline/src/main/java/org/apache/felix/gogo/jline/Posix.java
    
felix/trunk/gogo/jline/src/main/java/org/apache/felix/gogo/jline/Procedural.java
    felix/trunk/gogo/jline/src/main/java/org/apache/felix/gogo/jline/Shell.java
    
felix/trunk/gogo/jline/src/main/java/org/apache/felix/gogo/jline/ssh/ShellFactoryImpl.java
    
felix/trunk/gogo/jline/src/main/java/org/apache/felix/gogo/jline/telnet/Telnet.java

Modified: 
felix/trunk/gogo/jline/src/main/java/org/apache/felix/gogo/jline/Activator.java
URL: 
http://svn.apache.org/viewvc/felix/trunk/gogo/jline/src/main/java/org/apache/felix/gogo/jline/Activator.java?rev=1736006&r1=1736005&r2=1736006&view=diff
==============================================================================
--- 
felix/trunk/gogo/jline/src/main/java/org/apache/felix/gogo/jline/Activator.java 
(original)
+++ 
felix/trunk/gogo/jline/src/main/java/org/apache/felix/gogo/jline/Activator.java 
Mon Mar 21 16:54:22 2016
@@ -25,7 +25,6 @@ import java.util.Iterator;
 import java.util.Set;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
-import java.util.concurrent.ThreadFactory;
 import java.util.concurrent.TimeUnit;
 
 import org.apache.felix.gogo.jline.Shell.Context;
@@ -47,7 +46,7 @@ public class Activator implements Bundle
     private ExecutorService executor;
 
     public Activator() {
-        regs = new HashSet<ServiceRegistration>();
+        regs = new HashSet<>();
     }
 
     public void start(BundleContext context) throws Exception {
@@ -87,7 +86,7 @@ public class Activator implements Bundle
     }
 
     private void startShell(final BundleContext context, CommandProcessor 
processor) {
-        Dictionary<String, Object> dict = new Hashtable<String, Object>();
+        Dictionary<String, Object> dict = new Hashtable<>();
         dict.put(CommandProcessor.COMMAND_SCOPE, "gogo");
 
         // register converters
@@ -102,21 +101,17 @@ public class Activator implements Bundle
         regs.add(context.registerService(Procedural.class.getName(), new 
Procedural(), dict));
 
         dict.put(CommandProcessor.COMMAND_FUNCTION, Posix.functions);
-        regs.add(context.registerService(Posix.class.getName(), new Posix(), 
dict));
+        regs.add(context.registerService(Posix.class.getName(), new 
Posix(processor), dict));
 
         dict.put(CommandProcessor.COMMAND_FUNCTION, Telnet.functions);
         regs.add(context.registerService(Telnet.class.getName(), new 
Telnet(processor), dict));
 
-        Shell shell = new Shell(new ShellContext(), processor, null);
+        Shell shell = new Shell(new ShellContext(), processor);
         dict.put(CommandProcessor.COMMAND_FUNCTION, Shell.functions);
         regs.add(context.registerService(Shell.class.getName(), shell, dict));
 
         // start shell on a separate thread...
-        executor = Executors.newSingleThreadExecutor(new ThreadFactory() {
-            public Thread newThread(Runnable runnable) {
-                return new Thread(runnable, "Gogo shell");
-            }
-        });
+        executor = Executors.newSingleThreadExecutor(runnable -> new 
Thread(runnable, "Gogo shell"));
         executor.submit(new StartShellJob(context, processor));
     }
 

Modified: 
felix/trunk/gogo/jline/src/main/java/org/apache/felix/gogo/jline/Builtin.java
URL: 
http://svn.apache.org/viewvc/felix/trunk/gogo/jline/src/main/java/org/apache/felix/gogo/jline/Builtin.java?rev=1736006&r1=1736005&r2=1736006&view=diff
==============================================================================
--- 
felix/trunk/gogo/jline/src/main/java/org/apache/felix/gogo/jline/Builtin.java 
(original)
+++ 
felix/trunk/gogo/jline/src/main/java/org/apache/felix/gogo/jline/Builtin.java 
Mon Mar 21 16:54:22 2016
@@ -20,8 +20,11 @@ package org.apache.felix.gogo.jline;
 
 import java.io.BufferedReader;
 import java.io.BufferedWriter;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.io.InputStreamReader;
+import java.io.PrintStream;
 import java.io.StringWriter;
 import java.lang.reflect.Constructor;
 import java.lang.reflect.Field;
@@ -43,21 +46,39 @@ import java.util.Map.Entry;
 import java.util.Set;
 import java.util.TreeMap;
 import java.util.TreeSet;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
 
+import org.apache.felix.gogo.runtime.CommandSessionImpl;
 import org.apache.felix.gogo.runtime.Job;
 import org.apache.felix.service.command.CommandSession;
 import org.apache.felix.service.command.Converter;
+import org.apache.felix.service.command.Function;
+import org.jline.builtins.Commands;
+import org.jline.builtins.Completers.DirectoriesCompleter;
+import org.jline.builtins.Completers.FilesCompleter;
 import org.jline.builtins.Options;
+import org.jline.reader.Candidate;
+import org.jline.reader.LineReader;
+import org.jline.reader.ParsedLine;
+import org.jline.reader.Widget;
+
+import static org.apache.felix.gogo.jline.Shell.*;
 
 /**
  * gosh built-in commands.
  */
 public class Builtin {
 
-    static final String[] functions = {"format", "getopt", "new", "set", 
"tac", "type", "jobs", "fg", "bg"};
+    static final String[] functions = {
+            "format", "getopt", "new", "set", "tac", "type",
+            "jobs", "fg", "bg",
+            "keymap", "setopt", "unsetopt", "complete", "history", "widget",
+            "__files", "__directories", "__usage_completion"
+    };
+
+    private static final String[] packages = {"java.lang", "java.io", 
"java.net", "java.util"};
 
-    private static final String[] packages = {"java.lang", "java.io", 
"java.net",
-            "java.util"};
     private final static Set<String> KEYWORDS = new HashSet<String>(
             Arrays.asList(new String[]{"abstract", "continue", "for", "new", 
"switch",
                     "assert", "default", "goto", "package", "synchronized", 
"boolean", "do",
@@ -68,11 +89,6 @@ public class Builtin {
                     "finally", "long", "strictfp", "volatile", "const", 
"float", "native",
                     "super", "while"}));
 
-    @SuppressWarnings("unchecked")
-    static Set<String> getCommands(CommandSession session) {
-        return (Set<String>) session.get(".commands");
-    }
-
     public CharSequence format(CommandSession session) {
         return format(session, session.get("_"));    // last result
     }
@@ -564,4 +580,133 @@ public class Builtin {
         return list;
     }
 
+    public void history(CommandSession session, String[] argv) throws 
IOException {
+        Commands.history(Shell.getReader(session), System.out, System.err, 
argv);
+    }
+
+    public void complete(CommandSession session, String[] argv) {
+        Commands.complete(Shell.getReader(session), System.out, System.err, 
Shell.getCompletions(session), argv);
+    }
+
+    public void widget(final CommandSession session, String[] argv) throws 
Exception {
+        java.util.function.Function<String, Widget> creator = func -> () -> {
+            try {
+                session.execute(func);
+            } catch (Exception e) {
+                // TODO: log exception ?
+                return false;
+            }
+            return true;
+        };
+        Commands.widget(Shell.getReader(session), System.out, System.err, 
creator, argv);
+    }
+
+    public void keymap(CommandSession session, String[] argv) {
+        Commands.keymap(Shell.getReader(session), System.out, System.err, 
argv);
+    }
+
+    public void setopt(CommandSession session, String[] argv) {
+        Commands.setopt(Shell.getReader(session), System.out, System.err, 
argv);
+    }
+
+    public void unsetopt(CommandSession session, String[] argv) {
+        Commands.unsetopt(Shell.getReader(session), System.out, System.err, 
argv);
+    }
+
+    public List<Candidate> __files(CommandSession session) {
+        ParsedLine line = Shell.getParsedLine(session);
+        LineReader reader = Shell.getReader(session);
+        List<Candidate> candidates = new ArrayList<>();
+        new FilesCompleter(session.currentDir()) {
+            @Override
+            protected String getDisplay(Path p) {
+                return getFileDisplay(session, p);
+            }
+        }.complete(reader, line, candidates);
+        return candidates;
+    }
+
+    public List<Candidate> __directories(CommandSession session) {
+        ParsedLine line = Shell.getParsedLine(session);
+        LineReader reader = Shell.getReader(session);
+        List<Candidate> candidates = new ArrayList<>();
+        new DirectoriesCompleter(session.currentDir()) {
+            @Override
+            protected String getDisplay(Path p) {
+                return getFileDisplay(session, p);
+            }
+        }.complete(reader, line, candidates);
+        return candidates;
+    }
+
+    private String getFileDisplay(CommandSession session, Path path) {
+        String type;
+        String suffix;
+        if (Files.isSymbolicLink(path)) {
+            type = "sl";
+            suffix = "@";
+        } else if (Files.isDirectory(path)) {
+            type = "dr";
+            suffix = "/";
+        } else if (Files.isExecutable(path)) {
+            type = "ex";
+            suffix = "*";
+        } else if (!Files.isRegularFile(path)) {
+            type = "ot";
+            suffix = "";
+        } else {
+            type = "";
+            suffix = "";
+        }
+        String col = Posix.getColorMap(session, "LS").get(type);
+        if (col != null && !col.isEmpty()) {
+            return "\033[" + col + "m" + path.getFileName().toString() + 
"\033[m" + suffix;
+        } else {
+            return path.getFileName().toString() + suffix;
+        }
+
+    }
+
+    public void __usage_completion(CommandSession session, String command) 
throws Exception {
+        Object func = session.get(command.contains(":") ? command : "*:" + 
command);
+        if (func instanceof Function) {
+            ByteArrayInputStream bais = new ByteArrayInputStream(new byte[0]);
+            ByteArrayOutputStream baos = new ByteArrayOutputStream();
+            ByteArrayOutputStream baes = new ByteArrayOutputStream();
+            CommandSession ts = ((CommandSessionImpl) 
session).processor().createSession(bais, new PrintStream(baos), new 
PrintStream(baes));
+            ts.execute(command + " --help");
+
+            String regex = "(?x)\\s*" + "(?:-([^-]))?" +  // 1: short-opt-1
+                    "(?:,?\\s*-(\\w))?" +                 // 2: short-opt-2
+                    "(?:,?\\s*--(\\w[\\w-]*)(=\\w+)?)?" + // 3: long-opt-1 and 
4:arg-1
+                    "(?:,?\\s*--(\\w[\\w-]*))?" +         // 5: long-opt-2
+                    ".*?(?:\\(default=(.*)\\))?\\s*" +    // 6: default
+                    "(.*)";                               // 7: description
+            Pattern pattern = Pattern.compile(regex);
+            for (String l : baes.toString().split("\n")) {
+                Matcher matcher = pattern.matcher(l);
+                if (matcher.matches()) {
+                    List<String> args = new ArrayList<>();
+                    if (matcher.group(1) != null) {
+                        args.add("--short-option");
+                        args.add(matcher.group(1));
+                    }
+                    if (matcher.group(3) != null) {
+                        args.add("--long-option");
+                        args.add(matcher.group(1));
+                    }
+                    if (matcher.group(4) != null) {
+                        args.add("--argument");
+                        args.add("");
+                    }
+                    if (matcher.group(7) != null) {
+                        args.add("--description");
+                        args.add(matcher.group(7));
+                    }
+                    complete(session, args.toArray(new String[args.size()]));
+                }
+            }
+        }
+    }
+
 }

Modified: 
felix/trunk/gogo/jline/src/main/java/org/apache/felix/gogo/jline/Highlighter.java
URL: 
http://svn.apache.org/viewvc/felix/trunk/gogo/jline/src/main/java/org/apache/felix/gogo/jline/Highlighter.java?rev=1736006&r1=1736005&r2=1736006&view=diff
==============================================================================
--- 
felix/trunk/gogo/jline/src/main/java/org/apache/felix/gogo/jline/Highlighter.java
 (original)
+++ 
felix/trunk/gogo/jline/src/main/java/org/apache/felix/gogo/jline/Highlighter.java
 Mon Mar 21 16:54:22 2016
@@ -103,7 +103,6 @@ public class Highlighter extends Default
                     break;
                 }
                 if (token.start() > cur) {
-//                    ansi.a(buffer.substring(cur, token.start()));
                     cur = token.start();
                 }
                 // Find corresponding statement
@@ -153,37 +152,6 @@ public class Highlighter extends Default
                     }
                 }
                 Arrays.fill(types, token.start(), Math.min(token.start() + 
token.length(), types.length), type);
-                /*
-                String valid;
-                if (token.start() + token.length() <= buffer.length()) {
-                    valid = token.toString();
-                } else {
-                    valid = token.subSequence(0, buffer.length() - 
token.start()).toString();
-                }
-                switch (type) {
-                    case Reserved:
-                        ansi.fg(Color.MAGENTA).a(valid).fg(Color.DEFAULT);
-                        break;
-                    case String:
-                    case Number:
-                    case Constant:
-                        ansi.fg(Color.GREEN).a(valid).fg(Color.DEFAULT);
-                        break;
-                    case Variable:
-                    case VariableName:
-                        ansi.fg(Color.CYAN).a(valid).fg(Color.DEFAULT);
-                        break;
-                    case Function:
-                        ansi.fg(Color.BLUE).a(valid).fg(Color.DEFAULT);
-                        break;
-                    case BadFunction:
-                        ansi.fg(Color.RED).a(valid).fg(Color.DEFAULT);
-                        break;
-                    default:
-                        ansi.a(valid);
-                        break;
-                }
-                */
                 cur = Math.min(token.start() + token.length(), 
buffer.length());
             }
 

Modified: 
felix/trunk/gogo/jline/src/main/java/org/apache/felix/gogo/jline/Main.java
URL: 
http://svn.apache.org/viewvc/felix/trunk/gogo/jline/src/main/java/org/apache/felix/gogo/jline/Main.java?rev=1736006&r1=1736005&r2=1736006&view=diff
==============================================================================
--- felix/trunk/gogo/jline/src/main/java/org/apache/felix/gogo/jline/Main.java 
(original)
+++ felix/trunk/gogo/jline/src/main/java/org/apache/felix/gogo/jline/Main.java 
Mon Mar 21 16:54:22 2016
@@ -49,15 +49,14 @@ public class Main {
             try {
                 CommandProcessorImpl processor = new CommandProcessorImpl(tio);
                 Context context = new MyContext();
-                Shell shell = new Shell(context, processor, terminal);
+                Shell shell = new Shell(context, processor);
                 processor.addCommand("gogo", processor, "addCommand");
                 processor.addCommand("gogo", processor, "removeCommand");
                 processor.addCommand("gogo", processor, "eval");
                 register(processor, new Builtin(), Builtin.functions);
                 register(processor, new Procedural(), Procedural.functions);
-                register(processor, new Posix(), Posix.functions);
+                register(processor, new Posix(processor), Posix.functions);
                 register(processor, shell, Shell.functions);
-                register(processor, new JLineCommands(processor), 
JLineCommands.functions);
                 try {
                     register(processor, new Telnet(processor), 
Telnet.functions);
                 } catch (Throwable t) {

Modified: 
felix/trunk/gogo/jline/src/main/java/org/apache/felix/gogo/jline/ParsedLineImpl.java
URL: 
http://svn.apache.org/viewvc/felix/trunk/gogo/jline/src/main/java/org/apache/felix/gogo/jline/ParsedLineImpl.java?rev=1736006&r1=1736005&r2=1736006&view=diff
==============================================================================
--- 
felix/trunk/gogo/jline/src/main/java/org/apache/felix/gogo/jline/ParsedLineImpl.java
 (original)
+++ 
felix/trunk/gogo/jline/src/main/java/org/apache/felix/gogo/jline/ParsedLineImpl.java
 Mon Mar 21 16:54:22 2016
@@ -38,7 +38,7 @@ public class ParsedLineImpl implements P
         this.program = program;
         this.source = line.toString();
         this.cursor = cursor - line.start();
-        this.tokens = new ArrayList<String>();
+        this.tokens = new ArrayList<>();
         for (Token token : tokens) {
             this.tokens.add(token.toString());
         }

Modified: 
felix/trunk/gogo/jline/src/main/java/org/apache/felix/gogo/jline/Posix.java
URL: 
http://svn.apache.org/viewvc/felix/trunk/gogo/jline/src/main/java/org/apache/felix/gogo/jline/Posix.java?rev=1736006&r1=1736005&r2=1736006&view=diff
==============================================================================
--- felix/trunk/gogo/jline/src/main/java/org/apache/felix/gogo/jline/Posix.java 
(original)
+++ felix/trunk/gogo/jline/src/main/java/org/apache/felix/gogo/jline/Posix.java 
Mon Mar 21 16:54:22 2016
@@ -19,15 +19,19 @@
 package org.apache.felix.gogo.jline;
 
 import java.io.BufferedReader;
+import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
+import java.io.File;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.InputStreamReader;
+import java.io.OutputStream;
 import java.io.PrintStream;
 import java.nio.file.FileVisitOption;
 import java.nio.file.FileVisitResult;
 import java.nio.file.FileVisitor;
 import java.nio.file.Files;
+import java.nio.file.LinkOption;
 import java.nio.file.Path;
 import java.nio.file.PathMatcher;
 import java.nio.file.attribute.BasicFileAttributes;
@@ -48,6 +52,9 @@ import java.util.Map;
 import java.util.Objects;
 import java.util.Set;
 import java.util.TreeMap;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
 import java.util.function.Consumer;
 import java.util.function.IntBinaryOperator;
 import java.util.function.Predicate;
@@ -56,17 +63,22 @@ import java.util.regex.Pattern;
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
 
+import org.apache.felix.gogo.jline.Shell.Context;
 import org.apache.felix.gogo.runtime.Pipe;
+import org.apache.felix.service.command.CommandProcessor;
 import org.apache.felix.service.command.CommandSession;
+import org.apache.sshd.common.util.OsUtils;
+import org.jline.builtins.Commands;
 import org.jline.builtins.Less.Source;
 import org.jline.builtins.Less.StdInSource;
 import org.jline.builtins.Less.URLSource;
 import org.jline.builtins.Options;
-import org.jline.reader.LineReader.Option;
+import org.jline.terminal.Attributes;
 import org.jline.terminal.Terminal;
 import org.jline.utils.AttributedString;
 import org.jline.utils.AttributedStringBuilder;
 import org.jline.utils.AttributedStyle;
+import org.jline.utils.InfoCmp.Capability;
 
 /**
  * Posix-like utilities.
@@ -75,42 +87,31 @@ import org.jline.utils.AttributedStyle;
  * http://www.opengroup.org/onlinepubs/009695399/utilities/contents.html</a>
  */
 public class Posix {
-    static final String[] functions = {"cat", "echo", "grep", "sort", "sleep", 
"cd", "pwd", "ls"};
+
+    static final String[] functions = {
+            "cat", "echo", "grep", "sort", "sleep", "cd", "pwd", "ls",
+            "less", "watch", "nano", "tmux",
+    };
 
     public static final String DEFAULT_LS_COLORS = 
"dr=1;91:ex=1;92:sl=1;96:ot=34;43";
 
-    public void _main(CommandSession session, String[] argv) {
+    private static final LinkOption[] NO_FOLLOW_OPTIONS = new 
LinkOption[]{LinkOption.NOFOLLOW_LINKS};
+    private static final List<String> WINDOWS_EXECUTABLE_EXTENSIONS = 
Collections.unmodifiableList(Arrays.asList(".bat", ".exe", ".cmd"));
+    private static final LinkOption[] EMPTY_LINK_OPTIONS = new LinkOption[0];
+
+    private final CommandProcessor processor;
+
+    public Posix(CommandProcessor processor) {
+        this.processor = processor;
+    }
+
+    protected void _main(CommandSession session, String[] argv) {
         if (argv == null || argv.length < 1) {
             throw new IllegalArgumentException();
         }
         try {
             argv = expand(session, argv);
-            switch (argv[0]) {
-                case "cat":
-                    cat(session, argv);
-                    break;
-                case "echo":
-                    echo(session, argv);
-                    break;
-                case "grep":
-                    grep(session, argv);
-                    break;
-                case "sort":
-                    sort(session, argv);
-                    break;
-                case "sleep":
-                    sleep(session, argv);
-                    break;
-                case "cd":
-                    cd(session, argv);
-                    break;
-                case "pwd":
-                    pwd(session, argv);
-                    break;
-                case "ls":
-                    ls(session, argv);
-                    break;
-            }
+            run(session, argv);
         } catch (IllegalArgumentException e) {
             System.err.println(e.getMessage());
             Pipe.error(2);
@@ -129,6 +130,243 @@ public class Posix {
         }
     }
 
+    protected Options parseOptions(CommandSession session, String[] usage, 
Object[] argv) throws Exception {
+        Options opt = Options.compile(usage, s -> get(session, s)).parse(argv, 
true);
+        if (opt.isSet("help")) {
+            ByteArrayOutputStream baos = new ByteArrayOutputStream();
+            opt.usage(new PrintStream(baos));
+            throw new HelpException(baos.toString());
+        }
+        return opt;
+    }
+
+    protected String get(CommandSession session, String name) {
+        Object o = session.get(name);
+        return o != null ? o.toString() : null;
+    }
+
+    protected String[] expand(CommandSession session, String[] argv) throws 
IOException {
+        String reserved = "(?<!\\\\)[*(|<\\[?]";
+        List<String> params = new ArrayList<>();
+        for (String arg : argv) {
+            if (arg.matches(".*" + reserved + ".*")) {
+                String org = arg;
+                List<String> expanded = new ArrayList<>();
+                Path currentDir = session.currentDir();
+                Path dir;
+                String pfx = arg.replaceFirst(reserved + ".*", "");
+                String prefix;
+                if (pfx.indexOf('/') >= 0) {
+                    pfx = pfx.substring(0, pfx.lastIndexOf('/'));
+                    arg = arg.substring(pfx.length() + 1);
+                    dir = currentDir.resolve(pfx).normalize();
+                    prefix = pfx + "/";
+                } else {
+                    dir = currentDir;
+                    prefix = "";
+                }
+                PathMatcher matcher = 
dir.getFileSystem().getPathMatcher("glob:" + arg);
+                Files.walkFileTree(dir,
+                        EnumSet.of(FileVisitOption.FOLLOW_LINKS),
+                        Integer.MAX_VALUE,
+                        new FileVisitor<Path>() {
+                            @Override
+                            public FileVisitResult preVisitDirectory(Path 
file, BasicFileAttributes attrs) throws IOException {
+                                if (file.equals(dir)) {
+                                    return FileVisitResult.CONTINUE;
+                                }
+                                if (Files.isHidden(file)) {
+                                    return FileVisitResult.SKIP_SUBTREE;
+                                }
+                                Path r = dir.relativize(file);
+                                if (matcher.matches(r)) {
+                                    expanded.add(prefix + r.toString());
+                                }
+                                return FileVisitResult.CONTINUE;
+                            }
+
+                            @Override
+                            public FileVisitResult visitFile(Path file, 
BasicFileAttributes attrs) throws IOException {
+                                if (!Files.isHidden(file)) {
+                                    Path r = dir.relativize(file);
+                                    if (matcher.matches(r)) {
+                                        expanded.add(prefix + r.toString());
+                                    }
+                                }
+                                return FileVisitResult.CONTINUE;
+                            }
+
+                            @Override
+                            public FileVisitResult visitFileFailed(Path file, 
IOException exc) throws IOException {
+                                return FileVisitResult.CONTINUE;
+                            }
+
+                            @Override
+                            public FileVisitResult postVisitDirectory(Path 
dir, IOException exc) throws IOException {
+                                return FileVisitResult.CONTINUE;
+                            }
+                        });
+                Collections.sort(expanded);
+                if (expanded.isEmpty()) {
+                    throw new IOException("no matches found: " + org);
+                }
+                params.addAll(expanded);
+            } else {
+                params.add(arg);
+            }
+        }
+        return params.toArray(new String[params.size()]);
+    }
+
+    protected Object run(CommandSession session, String[] argv) throws 
Exception {
+        switch (argv[0]) {
+            case "cat":
+                cat(session, argv);
+                break;
+            case "echo":
+                echo(session, argv);
+                break;
+            case "grep":
+                grep(session, argv);
+                break;
+            case "sort":
+                sort(session, argv);
+                break;
+            case "sleep":
+                sleep(session, argv);
+                break;
+            case "cd":
+                cd(session, argv);
+                break;
+            case "pwd":
+                pwd(session, argv);
+                break;
+            case "ls":
+                ls(session, argv);
+                break;
+            case "less":
+                less(session, argv);
+                break;
+            case "watch":
+                watch(session, argv);
+                break;
+            case "nano":
+                nano(session, argv);
+                break;
+            case "tmux":
+                tmux(session, argv);
+                break;
+        }
+        return null;
+    }
+
+    protected void tmux(final CommandSession session, String[] argv) throws 
Exception {
+        Commands.tmux(Shell.getTerminal(session),
+                System.out, System.err,
+                () -> session.get(".tmux"),
+                t -> session.put(".tmux", t),
+                c -> startShell(session, c), argv);
+    }
+
+    private void startShell(CommandSession session, Terminal terminal) {
+        new Thread(() -> runShell(session, terminal), terminal.getName() + " 
shell").start();
+    }
+
+    private void runShell(CommandSession session, Terminal terminal) {
+        InputStream in = terminal.input();
+        OutputStream out = terminal.output();
+        CommandSession newSession = processor.createSession(in, out, out);
+        newSession.put(Shell.VAR_TERMINAL, terminal);
+        newSession.put(".tmux", session.get(".tmux"));
+        Context context = new Context() {
+            public String getProperty(String name) {
+                return System.getProperty(name);
+            }
+            public void exit() throws Exception {
+                terminal.close();
+            }
+        };
+        try {
+            new Shell(context, processor).gosh(newSession, new 
String[]{"--login"});
+        } catch (Exception e) {
+            e.printStackTrace();
+        } finally {
+            try {
+                terminal.close();
+            } catch (IOException e) {
+                e.printStackTrace();
+            }
+        }
+    }
+
+    protected void nano(final CommandSession session, String[] argv) throws 
Exception {
+        Commands.nano(Shell.getTerminal(session), System.out, System.err, 
session.currentDir(), argv);
+    }
+
+    protected void watch(final CommandSession session, String[] argv) throws 
IOException, InterruptedException {
+        final String[] usage = {
+                "watch - watches & refreshes the output of a command",
+                "Usage: watch [OPTIONS] COMMAND",
+                "  -? --help                    Show help",
+                "  -n --interval                Interval between executions of 
the command in seconds",
+                "  -a --append                  The output should be appended 
but not clear the console"
+        };
+        final Options opt = Options.compile(usage).parse(argv);
+        if (opt.isSet("help")) {
+            opt.usage(System.err);
+            return;
+        }
+        List<String> args = opt.args();
+        if (args.isEmpty()) {
+            System.err.println("Argument expected");
+            return;
+        }
+        ScheduledExecutorService executorService = 
Executors.newSingleThreadScheduledExecutor();
+        final Terminal terminal = Shell.getTerminal(session);
+        final CommandProcessor processor = Shell.getProcessor(session);
+        try {
+            int interval = 1;
+            if (opt.isSet("interval")) {
+                interval = opt.getNumber("interval");
+                if (interval < 1) {
+                    interval = 1;
+                }
+            }
+            final String cmd = String.join(" ", args);
+            Runnable task = () -> {
+                ByteArrayOutputStream baos = new ByteArrayOutputStream();
+                PrintStream os = new PrintStream(baos);
+                InputStream is = new ByteArrayInputStream(new byte[0]);
+                if (opt.isSet("append") || 
!terminal.puts(Capability.clear_screen)) {
+                    terminal.writer().println();
+                }
+                try {
+                    CommandSession ns = processor.createSession(is, os, os);
+                    Set<String> vars = Shell.getCommands(session);
+                    for (String n : vars) {
+                        ns.put(n, session.get(n));
+                    }
+                    ns.execute(cmd);
+                } catch (Throwable t) {
+                    t.printStackTrace(os);
+                }
+                os.flush();
+                terminal.writer().print(baos.toString());
+                terminal.writer().flush();
+            };
+            executorService.scheduleAtFixedRate(task, 0, interval, 
TimeUnit.SECONDS);
+            Attributes attr = terminal.enterRawMode();
+            terminal.reader().read();
+            terminal.setAttributes(attr);
+        } finally {
+            executorService.shutdownNow();
+        }
+    }
+
+    protected void less(CommandSession session, String[] argv) throws 
IOException, InterruptedException {
+        Commands.less(Shell.getTerminal(session), System.out, System.err, 
session.currentDir(), argv);
+    }
+
     protected void sort(CommandSession session, String[] argv) throws 
Exception {
         final String[] usage = {
                 "sort -  writes sorted standard input to standard output.",
@@ -403,14 +641,14 @@ public class Posix {
                 for (String view : 
path.getFileSystem().supportedFileAttributeViews()) {
                     try {
                         Map<String, Object> ta = Files.readAttributes(path, 
view + ":*",
-                                IoUtils.getLinkOptions(opt.isSet("L")));
+                                getLinkOptions(opt.isSet("L")));
                         ta.entrySet().forEach(e -> 
attrs.putIfAbsent(e.getKey(), e.getValue()));
                     } catch (IOException e) {
                         // Ignore
                     }
                 }
                 attrs.computeIfAbsent("isExecutable", s -> 
Files.isExecutable(path));
-                attrs.computeIfAbsent("permissions", s -> 
IoUtils.getPermissionsFromFile(path.toFile()));
+                attrs.computeIfAbsent("permissions", s -> 
getPermissionsFromFile(path.toFile()));
                 return attrs;
             }
         }
@@ -613,7 +851,7 @@ public class Posix {
         if (before < 0) {
             before = context;
         }
-        List<String> lines = new ArrayList<String>();
+        List<String> lines = new ArrayList<>();
         boolean invertMatch = opt.isSet("invert-match");
         boolean lineNumber = opt.isSet("line-number");
         boolean count = opt.isSet("count");
@@ -785,10 +1023,7 @@ public class Posix {
                 sortFields = new ArrayList<>();
                 sortFields.add("1");
             }
-            sortKeys = new ArrayList<Key>();
-            for (String f : sortFields) {
-                sortKeys.add(new Key(f));
-            }
+            sortKeys = 
sortFields.stream().map(Key::new).collect(Collectors.toList());
         }
 
         public int compare(String o1, String o2) {
@@ -823,8 +1058,7 @@ public class Posix {
         }
 
         protected int compareRegion(String s1, int start1, int end1, String 
s2, int start2, int end2, boolean caseInsensitive) {
-            int n1 = end1, n2 = end2;
-            for (int i1 = start1, i2 = start2; i1 < end1 && i2 < n2; i1++, 
i2++) {
+            for (int i1 = start1, i2 = start2; i1 < end1 && i2 < end2; i1++, 
i2++) {
                 char c1 = s1.charAt(i1);
                 char c2 = s2.charAt(i2);
                 if (c1 != c2) {
@@ -843,7 +1077,7 @@ public class Posix {
                     }
                 }
             }
-            return n1 - n2;
+            return end1 - end2;
         }
 
         protected int[] getSortKey(String str, List<Integer> fields, Key key) {
@@ -882,7 +1116,6 @@ public class Posix {
             List<Integer> fields = new ArrayList<>();
             if (o.length() > 0) {
                 if (separator == '\0') {
-                    int i = 0;
                     fields.add(0);
                     for (int idx = 1; idx < o.length(); idx++) {
                         if (Character.isWhitespace(o.charAt(idx)) && 
!Character.isWhitespace(o.charAt(idx - 1))) {
@@ -1014,74 +1247,57 @@ public class Posix {
         }
     }
 
-    private String[] expand(CommandSession session, String[] argv) throws 
IOException {
-        String reserved = "(?<!\\\\)[*(|<\\[?]";
-        List<String> params = new ArrayList<>();
-        for (String arg : argv) {
-            if (arg.matches(".*" + reserved + ".*")) {
-                String org = arg;
-                List<String> expanded = new ArrayList<>();
-                Path currentDir = session.currentDir();
-                Path dir;
-                String pfx = arg.replaceFirst(reserved + ".*", "");
-                String prefix;
-                if (pfx.indexOf('/') >= 0) {
-                    pfx = pfx.substring(0, pfx.lastIndexOf('/'));
-                    arg = arg.substring(pfx.length() + 1);
-                    dir = currentDir.resolve(pfx).normalize();
-                    prefix = pfx + "/";
-                } else {
-                    dir = currentDir;
-                    prefix = "";
-                }
-                PathMatcher matcher = 
dir.getFileSystem().getPathMatcher("glob:" + arg);
-                Files.walkFileTree(dir,
-                        EnumSet.of(FileVisitOption.FOLLOW_LINKS),
-                        Integer.MAX_VALUE,
-                        new FileVisitor<Path>() {
-                    @Override
-                    public FileVisitResult preVisitDirectory(Path file, 
BasicFileAttributes attrs) throws IOException {
-                        if (file.equals(dir)) {
-                            return FileVisitResult.CONTINUE;
-                        }
-                        if (Files.isHidden(file)) {
-                            return FileVisitResult.SKIP_SUBTREE;
-                        }
-                        Path r = dir.relativize(file);
-                        if (matcher.matches(r)) {
-                            expanded.add(prefix + r.toString());
-                        }
-                        return FileVisitResult.CONTINUE;
-                    }
-                    @Override
-                    public FileVisitResult visitFile(Path file, 
BasicFileAttributes attrs) throws IOException {
-                        if (!Files.isHidden(file)) {
-                            Path r = dir.relativize(file);
-                            if (matcher.matches(r)) {
-                                expanded.add(prefix + r.toString());
-                            }
-                        }
-                        return FileVisitResult.CONTINUE;
-                    }
-                    @Override
-                    public FileVisitResult visitFileFailed(Path file, 
IOException exc) throws IOException {
-                        return FileVisitResult.CONTINUE;
-                    }
-                    @Override
-                    public FileVisitResult postVisitDirectory(Path dir, 
IOException exc) throws IOException {
-                        return FileVisitResult.CONTINUE;
-                    }
-                });
-                Collections.sort(expanded);
-                if (expanded.isEmpty()) {
-                    throw new IOException("no matches found: " + org);
-                }
-                params.addAll(expanded);
-            } else {
-                params.add(arg);
+    private static LinkOption[] getLinkOptions(boolean followLinks) {
+        if (followLinks) {
+            return EMPTY_LINK_OPTIONS;
+        } else {    // return a clone that modifications to the array will not 
affect others
+            return NO_FOLLOW_OPTIONS.clone();
+        }
+    }
+
+    /**
+     * @param fileName The file name to be evaluated - ignored if {@code 
null}/empty
+     * @return {@code true} if the file ends in one of the {@link 
#WINDOWS_EXECUTABLE_EXTENSIONS}
+     */
+    private static boolean isWindowsExecutable(String fileName) {
+        if ((fileName == null) || (fileName.length() <= 0)) {
+            return false;
+        }
+        for (String suffix : WINDOWS_EXECUTABLE_EXTENSIONS) {
+            if (fileName.endsWith(suffix)) {
+                return true;
             }
         }
-        return params.toArray(new String[params.size()]);
+        return false;
+    }
+
+    /**
+     * @param f The {@link File} to be checked
+     * @return A {@link Set} of {@link PosixFilePermission}s based on whether
+     * the file is readable/writable/executable. If so, then <U>all</U> the
+     * relevant permissions are set (i.e., owner, group and others)
+     */
+    private static Set<PosixFilePermission> getPermissionsFromFile(File f) {
+        Set<PosixFilePermission> perms = 
EnumSet.noneOf(PosixFilePermission.class);
+        if (f.canRead()) {
+            perms.add(PosixFilePermission.OWNER_READ);
+            perms.add(PosixFilePermission.GROUP_READ);
+            perms.add(PosixFilePermission.OTHERS_READ);
+        }
+
+        if (f.canWrite()) {
+            perms.add(PosixFilePermission.OWNER_WRITE);
+            perms.add(PosixFilePermission.GROUP_WRITE);
+            perms.add(PosixFilePermission.OTHERS_WRITE);
+        }
+
+        if (f.canExecute() || (OsUtils.isWin32() && 
isWindowsExecutable(f.getName()))) {
+            perms.add(PosixFilePermission.OWNER_EXECUTE);
+            perms.add(PosixFilePermission.GROUP_EXECUTE);
+            perms.add(PosixFilePermission.OTHERS_EXECUTE);
+        }
+
+        return perms;
     }
 
     public static Map<String, String> getColorMap(CommandSession session, 
String name) {
@@ -1099,19 +1315,4 @@ public class Posix {
                                           s -> s.substring(s.indexOf('=') + 
1)));
     }
 
-    private Options parseOptions(CommandSession session, String[] usage, 
Object[] argv) throws Exception {
-        Options opt = Options.compile(usage, s -> get(session, s)).parse(argv, 
true);
-        if (opt.isSet("help")) {
-            ByteArrayOutputStream baos = new ByteArrayOutputStream();
-            opt.usage(new PrintStream(baos));
-            throw new HelpException(baos.toString());
-        }
-        return opt;
-    }
-
-    private String get(CommandSession session, String name) {
-        Object o = session.get(name);
-        return o != null ? o.toString() : null;
-    }
-
 }

Modified: 
felix/trunk/gogo/jline/src/main/java/org/apache/felix/gogo/jline/Procedural.java
URL: 
http://svn.apache.org/viewvc/felix/trunk/gogo/jline/src/main/java/org/apache/felix/gogo/jline/Procedural.java?rev=1736006&r1=1736005&r2=1736006&view=diff
==============================================================================
--- 
felix/trunk/gogo/jline/src/main/java/org/apache/felix/gogo/jline/Procedural.java
 (original)
+++ 
felix/trunk/gogo/jline/src/main/java/org/apache/felix/gogo/jline/Procedural.java
 Mon Mar 21 16:54:22 2016
@@ -26,13 +26,13 @@ import org.apache.felix.service.command.
 import org.apache.felix.service.command.Function;
 
 public class Procedural {
-    static final String[] functions = {"each", "if", "not", "throw", "try", 
"until",
-            "while"};
+
+    static final String[] functions = {"each", "if", "not", "throw", "try", 
"until", "while"};
 
     public List<Object> each(CommandSession session, Collection<Object> list,
                              Function closure) throws Exception {
-        List<Object> args = new ArrayList<Object>();
-        List<Object> results = new ArrayList<Object>();
+        List<Object> args = new ArrayList<>();
+        List<Object> results = new ArrayList<>();
         args.add(null);
 
         for (Object x : list) {
@@ -61,11 +61,8 @@ public class Procedural {
     }
 
     public boolean not(CommandSession session, Function condition) throws 
Exception {
-        if (null == condition) {
-            return true;
-        }
+        return condition == null || !isTrue(condition.execute(session, null));
 
-        return !isTrue(condition.execute(session, null));
     }
 
     // Reflective.coerce() prefers to construct a new Throwable(String)
@@ -126,7 +123,7 @@ public class Procedural {
             return false;
 
         if (result instanceof Boolean)
-            return ((Boolean) result).booleanValue();
+            return (Boolean) result;
 
         if (result instanceof Number) {
             if (0 == ((Number) result).intValue())

Modified: 
felix/trunk/gogo/jline/src/main/java/org/apache/felix/gogo/jline/Shell.java
URL: 
http://svn.apache.org/viewvc/felix/trunk/gogo/jline/src/main/java/org/apache/felix/gogo/jline/Shell.java?rev=1736006&r1=1736005&r2=1736006&view=diff
==============================================================================
--- felix/trunk/gogo/jline/src/main/java/org/apache/felix/gogo/jline/Shell.java 
(original)
+++ felix/trunk/gogo/jline/src/main/java/org/apache/felix/gogo/jline/Shell.java 
Mon Mar 21 16:54:22 2016
@@ -53,6 +53,7 @@ import org.apache.felix.service.command.
 import org.apache.felix.service.command.Function;
 import org.apache.felix.service.command.Parameter;
 import org.jline.builtins.Completers.CompletionData;
+import org.jline.builtins.Completers.CompletionEnvironment;
 import org.jline.builtins.Options;
 import org.jline.reader.EndOfFileException;
 import org.jline.reader.LineReader;
@@ -88,11 +89,11 @@ public class Shell {
     private final Context context;
     private final CommandProcessor processor;
 
-    public Shell(Context context, CommandProcessor processor, Terminal 
terminal) {
-        this(context, processor, terminal, null);
+    public Shell(Context context, CommandProcessor processor) {
+        this(context, processor, null);
     }
 
-    public Shell(Context context, CommandProcessor processor, Terminal 
terminal, String profile) {
+    public Shell(Context context, CommandProcessor processor, String profile) {
         this.context = context;
         this.processor = processor;
         String baseDir = context.getProperty("gosh.home");
@@ -243,11 +244,9 @@ public class Shell {
         }
 
         // export variables starting with upper-case to newSession
-        for (String key : getVariables(session)) {
-            if (key.matches("[.]?[A-Z].*")) {
-                newSession.put(key, session.get(key));
-            }
-        }
+        getVariables(session).stream()
+                .filter(key -> key.matches("[.]?[A-Z].*"))
+                .forEach(key -> newSession.put(key, session.get(key)));
 
         Terminal terminal = getTerminal(session);
         newSession.put(Shell.VAR_CONTEXT, context);
@@ -261,10 +260,34 @@ public class Shell {
 
         LineReader reader;
         if (args.isEmpty() && interactive) {
+            CompletionEnvironment completionEnvironment = new 
CompletionEnvironment() {
+                @Override
+                public Map<String, List<CompletionData>> getCompletions() {
+                    return Shell.getCompletions(newSession);
+                }
+                @Override
+                public Set<String> getCommands() {
+                    return Shell.getCommands(session);
+                }
+                @Override
+                public String resolveCommand(String command) {
+                    return Shell.resolve(session, command);
+                }
+                @Override
+                public String commandName(String command) {
+                    int idx = command.indexOf(':');
+                    return idx >= 0 ? command.substring(idx + 1) : command;
+                }
+                @Override
+                public Object evaluate(LineReader reader, ParsedLine line, 
String func) throws Exception {
+                    session.put(Shell.VAR_COMMAND_LINE, line);
+                    return session.execute(func);
+                }
+            };
             reader = LineReaderBuilder.builder()
                     .terminal(terminal)
                     .variables(((CommandSessionImpl) 
newSession).getVariables())
-                    .completer(new org.jline.builtins.Completers.Completer(new 
JLineCompletionEnvironment(newSession)))
+                    .completer(new 
org.jline.builtins.Completers.Completer(completionEnvironment))
                     .highlighter(new Highlighter(session))
                     .history(new FileHistory(new 
File(System.getProperty("user.home"), ".gogo.history")))
                     .parser(new Parser())
@@ -357,6 +380,7 @@ public class Shell {
                             while (true) {
                                 Job job = session.foregroundJob();
                                 if (job != null) {
+                                    //noinspection 
SynchronizationOnLocalVariableOrMethodParameter
                                     synchronized (job) {
                                         if (job.status() == Status.Foreground) 
{
                                             job.wait();
@@ -420,6 +444,7 @@ public class Shell {
         return result;
     }
 
+    @Descriptor("start a new shell")
     public Object sh(final CommandSession session, String[] argv) throws 
Exception {
         return gosh(session, argv);
     }
@@ -428,6 +453,7 @@ public class Shell {
         context.exit();
     }
 
+    @Descriptor("Evaluates contents of file")
     public Object source(CommandSession session, String script) throws 
Exception {
         URI uri = session.currentDir().toUri().resolve(script);
         session.put("0", uri);
@@ -439,7 +465,7 @@ public class Shell {
     }
 
     private Map<String, List<Method>> getReflectionCommands(CommandSession 
session) {
-        Map<String, List<Method>> commands = new TreeMap<String, 
List<Method>>();
+        Map<String, List<Method>> commands = new TreeMap<>();
         Set<String> names = getCommands(session);
         for (String name : names) {
             Function function = (Function) session.get(name);
@@ -471,9 +497,7 @@ public class Shell {
     @Descriptor("displays available commands")
     public void help(CommandSession session) {
         Map<String, List<Method>> commands = getReflectionCommands(session);
-        for (String name : commands.keySet()) {
-            System.out.println(name);
-        }
+        commands.keySet().forEach(System.out::println);
     }
 
     @Descriptor("displays information about a specific command")
@@ -517,7 +541,7 @@ public class Shell {
                 Map<String, String> flagDescs = new TreeMap<>();
                 Map<String, Parameter> options = new TreeMap<>();
                 Map<String, String> optionDescs = new TreeMap<>();
-                List<String> params = new ArrayList<String>();
+                List<String> params = new ArrayList<>();
                 Annotation[][] anns = m.getParameterAnnotations();
                 for (int paramIdx = 0; paramIdx < anns.length; paramIdx++) {
                     Class<?> paramType = m.getParameterTypes()[paramIdx];

Modified: 
felix/trunk/gogo/jline/src/main/java/org/apache/felix/gogo/jline/ssh/ShellFactoryImpl.java
URL: 
http://svn.apache.org/viewvc/felix/trunk/gogo/jline/src/main/java/org/apache/felix/gogo/jline/ssh/ShellFactoryImpl.java?rev=1736006&r1=1736005&r2=1736006&view=diff
==============================================================================
--- 
felix/trunk/gogo/jline/src/main/java/org/apache/felix/gogo/jline/ssh/ShellFactoryImpl.java
 (original)
+++ 
felix/trunk/gogo/jline/src/main/java/org/apache/felix/gogo/jline/ssh/ShellFactoryImpl.java
 Mon Mar 21 16:54:22 2016
@@ -257,7 +257,7 @@ public class ShellFactoryImpl implements
                         destroy();
                     }
                 };
-                new Shell(context, processor, terminal).gosh(session, new 
String[]{"--login"});
+                new Shell(context, processor).gosh(session, new 
String[]{"--login"});
             } catch (Throwable t) {
                 t.printStackTrace();
             }

Modified: 
felix/trunk/gogo/jline/src/main/java/org/apache/felix/gogo/jline/telnet/Telnet.java
URL: 
http://svn.apache.org/viewvc/felix/trunk/gogo/jline/src/main/java/org/apache/felix/gogo/jline/telnet/Telnet.java?rev=1736006&r1=1736005&r2=1736006&view=diff
==============================================================================
--- 
felix/trunk/gogo/jline/src/main/java/org/apache/felix/gogo/jline/telnet/Telnet.java
 (original)
+++ 
felix/trunk/gogo/jline/src/main/java/org/apache/felix/gogo/jline/telnet/Telnet.java
 Mon Mar 21 16:54:22 2016
@@ -178,7 +178,7 @@ public class Telnet {
                                 close();
                             }
                         };
-                        new Shell(context, processor, terminal).gosh(session, 
new String[]{"--login"});
+                        new Shell(context, processor).gosh(session, new 
String[]{"--login"});
                     }
 
                     @Override


Reply via email to