Jump to content

readline use in CLI output


Auntie Mangos

Recommended Posts

Well, since CLI experience in mangos is lacking, i thought ill drop this patch that adds readline support under linux OS, with history of commands scrolling, and tab completion of commands. Some parts of the diff are hand-written (to get rid of trinityisms) so you may have to apply it manually. Also, remember to set up automake to link against readline ;)

--- a/src/game/Chat.h
+++ b/src/game/Chat.h
@@ -73,7 +73,7 @@ class ChatHandler
        int ParseCommands(const char* text);

        virtual char const* GetName() const;
-
+        static ChatCommand* getCommandTable();
    protected:
        explicit ChatHandler() : m_session(NULL) {}      // for CLI subclass

@@ -89,8 +89,6 @@ class ChatHandler
        bool ShowHelpForCommand(ChatCommand *table, const char* cmd);
        bool ShowHelpForSubCommands(ChatCommand *table, char const* cmd, char const* subcmd);

-        ChatCommand* getCommandTable();
-
        bool HandleAccountCommand(const char* args);
        bool HandleAccountCreateCommand(const char* args);
        bool HandleAccountDeleteCommand(const char* args);

--- a/src/trinitycore/CliRunnable.cpp
+++ b/src/trinitycore/CliRunnable.cpp
@@ -37,6 +37,56 @@
#include "Player.h"
#include "Chat.h"

+#if PLATFORM != WINDOWS
+#include <readline/readline.h>
+#include <readline/history.h>
+
+char * command_finder(const char* text, int state)
+{
+  static int idx,len;
+  const char* ret;
+  ChatCommand *cmd = ChatHandler::getCommandTable();
+
+  if(!state)
+    {
+      idx = 0;
+      len = strlen(text);
+    }
+
+  while(ret = cmd[idx].Name)
+    {
+      if(!cmd[idx].AllowConsole)
+    {
+    idx++;
+    continue;
+    }
+
+      idx++;
+      //printf("Checking %s \\n", cmd[idx].Name);
+      if (strncmp(ret, text, len) == 0)
+    return strdup(ret);
+      if(cmd[idx].Name == NULL)
+    break;
+    }
+
+  return ((char*)NULL);
+
+}
+
+char ** cli_completion(const char * text, int start, int end)
+{
+  char ** matches;
+  matches = (char**)NULL;
+  
+  if(start == 0)
+    matches = rl_completion_matches((char*)text,&command_finder);
+  else
+    rl_bind_key('\\t',rl_abort);
+  return (matches);
+}
+
+#endif
+
void utf8print(const char* str)
{
#if PLATFORM == PLATFORM_WINDOWS
@@ -316,10 +366,10 @@ void CliRunnable::run()
    WorldDatabase.ThreadStart();                                // let thread do safe mySQL requests

    char commandbuf[256];
-
+    bool canflush = true;
    ///- Display the list of available CLI functions then beep
    sLog.outString();
-
+    rl_attempted_completion_function = cli_completion;
    if(sConfig.GetBoolDefault("BeepAtStart", true))
        printf("\\a");                                       // \\a = Alert

@@ -331,15 +381,16 @@ void CliRunnable::run()
    while (!World::IsStopped())
    {
        fflush(stdout);
-        #ifdef linux
-        while (!kb_hit_return() && !World::IsStopped())
-            // With this, we limit CLI to 10commands/second
-            usleep(100);
-        if (World::IsStopped())
-            break;
-        #endif
-        char *command_str = fgets(commandbuf,sizeof(commandbuf),stdin);
-        if (command_str != NULL)
+
+        char *command_str ;             // = fgets(commandbuf,sizeof(commandbuf),stdin);
+
+    #if PLATFORM == WINDOWS
+    command_str = fgets(commandbuf,sizeof(commandbuf),stdin);
+    #else
+    command_str = readline("TC>");
+    rl_bind_key('\\t',rl_complete);
+    #endif
+    if (command_str != NULL)
        {
            for(int x=0;command_str[x];x++)
                if(command_str[x]=='\\r'||command_str[x]=='\\n')
@@ -351,23 +402,30 @@ void CliRunnable::run()

            if(!*command_str)
            {
-                printf("TC>");
+          #if PLATFORM == WINDOWS
+            printf("TC>");
+          #endif
                continue;
            }

            std::string command;
            if(!consoleToUtf8(command_str,command))         // convert from console encoding to utf8
            {
-                printf("TC>");
+          #if PLATFORM == WINDOWS
+            printf("TC>");
+          #endif
                continue;
            }
+        fflush(stdout);
+            sWorld.QueueCliCommand(&utf8print,command.c_str());
+                    #if PLATFORM != WINDOWS
+        add_history(command.c_str());
+                    #endif 

-            sWorld.QueueCliCommand(&utf8print,command.c_str());
-        }
+    }
        else if (feof(stdin))
        {
            World::StopNow(SHUTDOWN_EXIT_CODE);
        }
+
    }

    ///- End the database thread

[vladimir: extracted from http://getmangos.eu/community/showthread.php?p=36981#post36981 ]

Link to comment
Share on other sites

  • 39 years later...
Hmm, ... readline not installed at all UNIX as i understand

Yes and no, this library is used in tonnes of free software (bash, gdb, and so on...) But devel packages are still needed for building.

and then will need some configure code for use only if installed.

No, not at all. Configuration is optionall and it only overrides default behaviour.

Link to comment
Share on other sites

In other words, Vladimir wants something like an --enable-readline for configure.ac.

Last time i checked Vladimir could speak for himself

then in Makefile.am extend LDFLAGS with $( TERMLIB ).

That would allow us to use readline.

Thanks, i am by no means automake guy :)

Link to comment
Share on other sites

We could also change the library check to e.g. check for both ncurses and readline, and use whatever is available.

Might be an idea to support both, as either readline or ncurses always is available on Linux, and at least Fedora, openSUSE, and Debian (and derivatives) always include both by default.

Link to comment
Share on other sites

We could also change the library check to e.g. check for both ncurses and readline, and use whatever is available.

Might be an idea to support both, as either readline or ncurses always is available on Linux, and at least Fedora, openSUSE, and Debian (and derivatives) always include both by default.

It actually is the only idea to allow user to write and not get interrupted by log output. Question is what about windoze users?

Link to comment
Share on other sites

  • 7 months later...

For build it:

make ChatHandler::SetDataForCommandInTable static.

the line

bool canflush = true;

is useless.

the line

rl_attempted_completion_function = cli_completion;

must be online for no Windows system.

Apply the changes to configure and makefile, autoreconf, and build.

So actually it's not perfect, but history is appreciable.

Link to comment
Share on other sites

When I read the title of the thread I thought what the hell can this be. After that I tought "The MaNGOS command line should be modified to behave more properly". Well great work, keep it up.

Another thing that should need fixing is that the mangos> dissapears when there's other output, have you fixed this or ?

Link to comment
Share on other sites

  • 1 year later...
Guest
This topic is now closed to further replies.
×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue. Privacy Policy Terms of Use