]> cgit.babelmonkeys.de Git - jubjub.git/blobdiff - src/gui/cli/JubCLIUI.m
Add line editing support to the CLI UI
[jubjub.git] / src / gui / cli / JubCLIUI.m
index 6f0b03a68c5d51440a6c13d36b8f5850f7845a27..3cf59c2b05b96b5e5fb6a57ce528c4b77c7c6672 100644 (file)
@@ -4,6 +4,8 @@
 #import "JubCLICommand.h"
 #import "JubCLIUI.h"
 
+#include <string.h>
+
 BEGINCLICOMMAND(JubCLIReplyCommand, @":r", nil,
     @"Sets the sender of the last incomming message as the default recipient")
 {
@@ -177,11 +179,68 @@ ENDCLICOMMAND
        [super dealloc];
 }
 
+static JubCLIUI *completionData;
+static void completionCallback(OFString *buf, OFList *lc)
+{
+       if ([buf length] < 3)
+               return;
+
+       if (![buf hasPrefix: @":s "] && ![buf hasPrefix: @":m "] &&
+           ![buf hasPrefix: @":t "])
+               return;
+
+       if ([buf hasPrefix: @":t"]) {
+               OFString *options[] = {
+                       @":t available",
+                       @":t away",
+                       @":t dnd",
+                       @":t xa",
+                       @":t chat",
+                       @":t unavailable"
+               };
+
+               for (int i = 0; i < 6; i++) {
+                       if (![options[i] hasPrefix: buf])
+                               continue;
+                       [lc appendObject: options[i]];
+               }
+
+               return;
+       }
+
+       OFString *command = [buf substringWithRange: of_range(0, 3)];
+       OFString *query = [buf substringWithRange: of_range(3, [buf length]-3)];
+       OFDictionary *contacts = completionData.client.contactManager.contacts;
+       for (OFString *key in contacts) {
+               if (![key  hasPrefix: query])
+                       continue;
+               [lc appendObject: [command stringByAppendingString: key]];
+       }
+}
+
 - (void)startUIThread
 {
-       [of_stdin asyncReadLineWithTarget: self
-                                selector: @selector(Jub_userInputWithStream:
-                                                    line:exception:)];
+       completionData = self;
+
+       [[OFThread threadWithBlock: ^(void) {
+               OFString *line;
+               Linenoise *reader = [Linenoise sharedLinenoise];
+               reader.multiline = true;
+               reader.completionCallback = completionCallback;
+
+               while ((line = [reader readInputWithPrompt: @"> "]) != nil) @autoreleasepool {
+                       [self Jub_userInputWithStream: nil
+                                                line: line
+                                           exception: nil];
+                       if ([line length] != 0)
+                               [reader addHistoryItem: line];
+               }
+               [self Jub_userInputWithStream: nil
+                                        line: nil
+                                   exception: nil];
+
+               return nil;
+       }] start];
 }
 
 -      (void)client: (JubChatClient*)client
@@ -204,16 +263,18 @@ ENDCLICOMMAND
                           line: (OFString*)line
                      exception: (OFException*)exception
 {
-       if (line == nil)
+       if (line == nil || exception != nil)
                [OFApplication terminate];
 
        if ([line length] == 0)
                return YES;
 
        if ([line characterAtIndex: 0] != ':') {
-               if (_sink == nil)
+               if (_sink == nil) {
                        [of_stdout writeLine: @"No default sink selected, "
                            @"type `:h` for help"];
+                       return YES;
+               }
 
                [_sink send: line];
 
@@ -288,6 +349,7 @@ ENDCLICOMMAND
 -   (void)contact: (XMPPContact*)contact
   didSendPresence: (XMPPPresence*)presence
 {
+       [of_stdout writeFormat: @"\r"];
        [of_stdout writeFormat: BOLD("%@") @" is now in state ", presence.from];
 
        if ([presence.type isEqual: @"unavailable"])
@@ -307,5 +369,7 @@ ENDCLICOMMAND
                [of_stdout writeFormat: @": %@", presence.status];
 
        [of_stdout writeString: @"\n"];
+
+       [[Linenoise sharedLinenoise] refreshLine];
 }
 @end