You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@celix.apache.org by pn...@apache.org on 2017/11/12 20:13:42 UTC

celix git commit: CELIX-415: Refactors shell tui and ads support for configuring and detecting if ANSI control sequences are useable

Repository: celix
Updated Branches:
  refs/heads/develop 0a78d5d54 -> 7d3792212


CELIX-415: Refactors shell tui and ads support for configuring and detecting if ANSI control sequences are useable


Project: http://git-wip-us.apache.org/repos/asf/celix/repo
Commit: http://git-wip-us.apache.org/repos/asf/celix/commit/7d379221
Tree: http://git-wip-us.apache.org/repos/asf/celix/tree/7d379221
Diff: http://git-wip-us.apache.org/repos/asf/celix/diff/7d379221

Branch: refs/heads/develop
Commit: 7d379221262f4625faf62f3877a8192ec680638d
Parents: 0a78d5d
Author: Pepijn Noltes <pe...@gmail.com>
Authored: Sun Nov 12 21:21:23 2017 +0100
Committer: Pepijn Noltes <pe...@gmail.com>
Committed: Sun Nov 12 21:21:23 2017 +0100

----------------------------------------------------------------------
 .../private/include/dm_shell_list_command.h     |   8 +-
 .../private/src/dm_shell_activator.c            |  46 ++-
 .../private/src/dm_shell_list_command.c         |  18 +-
 dependency_manager/readme.md                    |  13 +
 .../public/include/service_tracker_customizer.h |   2 +
 shell_tui/README.md                             |  10 +-
 shell_tui/private/include/shell_tui.h           |  20 +-
 shell_tui/private/src/activator.c               |  86 +++--
 shell_tui/private/src/history.c                 |   7 -
 shell_tui/private/src/shell_tui.c               | 369 ++++++++++++-------
 10 files changed, 362 insertions(+), 217 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/celix/blob/7d379221/dependency_manager/private/include/dm_shell_list_command.h
----------------------------------------------------------------------
diff --git a/dependency_manager/private/include/dm_shell_list_command.h b/dependency_manager/private/include/dm_shell_list_command.h
index e8405c2..6ab0581 100644
--- a/dependency_manager/private/include/dm_shell_list_command.h
+++ b/dependency_manager/private/include/dm_shell_list_command.h
@@ -26,10 +26,14 @@ extern "C" {
 
 #include <stdlib.h>
 #include <string.h>
-
 #include "command.h"
 
-void dmListCommand_execute(bundle_context_pt context, char * line, FILE *out, FILE *err);
+typedef struct dm_command_handle {
+    bundle_context_pt context;
+    bool useColors;
+} dm_command_handle_t;
+
+void dmListCommand_execute(dm_command_handle_t* handle, char * line, FILE *out, FILE *err);
 
 #ifdef __cplusplus
 }

http://git-wip-us.apache.org/repos/asf/celix/blob/7d379221/dependency_manager/private/src/dm_shell_activator.c
----------------------------------------------------------------------
diff --git a/dependency_manager/private/src/dm_shell_activator.c b/dependency_manager/private/src/dm_shell_activator.c
index 43b8e3e..833051b 100644
--- a/dependency_manager/private/src/dm_shell_activator.c
+++ b/dependency_manager/private/src/dm_shell_activator.c
@@ -31,9 +31,12 @@
 
 #include "dm_shell_list_command.h"
 
+#define DM_SHELL_USE_ANSI_COLORS "DM_SHELL_USE_ANSI_COLORS"
+
 struct bundle_instance {
     service_registration_pt reg;
-    command_service_pt  dmCommand;
+    command_service_t  dmCommand;
+    dm_command_handle_t dmHandle;
 };
 
 typedef struct bundle_instance * bundle_instance_pt;
@@ -50,6 +53,11 @@ celix_status_t bundleActivator_create(bundle_context_pt context, void **userData
         return CELIX_ENOMEM;
     }
 
+    bi->dmHandle.context = context;
+    const char* config = NULL;
+    bundleContext_getPropertyWithDefault(context, DM_SHELL_USE_ANSI_COLORS, "true", &config);
+    bi->dmHandle.useColors = config != NULL && strncmp("true", config, 5) == 0;
+
     (*userData) = bi;
 
     return CELIX_SUCCESS;
@@ -58,27 +66,18 @@ celix_status_t bundleActivator_create(bundle_context_pt context, void **userData
 celix_status_t bundleActivator_start(void * userData, bundle_context_pt context) {
     celix_status_t status = CELIX_SUCCESS;
     bundle_instance_pt bi = (bundle_instance_pt) userData;
-    command_service_pt commandService = calloc(1, sizeof(*commandService));
-
-    if (commandService != NULL) {
-        commandService->handle = context;
-        commandService->executeCommand = (void *)dmListCommand_execute;
-
-        properties_pt props = properties_create();
-        properties_set(props, CELIX_FRAMEWORK_SERVICE_LANGUAGE, CELIX_FRAMEWORK_SERVICE_C_LANGUAGE);
-        properties_set(props, OSGI_SHELL_COMMAND_NAME, "dm");
-        properties_set(props, OSGI_SHELL_COMMAND_USAGE, "dm");
-        properties_set(props, OSGI_SHELL_COMMAND_DESCRIPTION,
-                       "Gives an overview of the component managemend by a dependency manager.");
-
-        bi->dmCommand = commandService;
-
-        status = bundleContext_registerService(context, (char *) OSGI_SHELL_COMMAND_SERVICE_NAME, commandService, props,
-                                               &bi->reg);
-    } else {
-        status = CELIX_ENOMEM;
-        free(commandService);
-    }
+
+    bi->dmCommand.handle = &bi->dmHandle;
+    bi->dmCommand.executeCommand = (void *)dmListCommand_execute;
+
+    properties_pt props = properties_create();
+    properties_set(props, CELIX_FRAMEWORK_SERVICE_LANGUAGE, CELIX_FRAMEWORK_SERVICE_C_LANGUAGE);
+    properties_set(props, OSGI_SHELL_COMMAND_NAME, "dm");
+    properties_set(props, OSGI_SHELL_COMMAND_USAGE, "dm");
+    properties_set(props, OSGI_SHELL_COMMAND_DESCRIPTION,
+                   "Gives an overview of the component managemend by a dependency manager.");
+
+    status = bundleContext_registerService(context, OSGI_SHELL_COMMAND_SERVICE_NAME, &bi->dmCommand, props, &bi->reg);
 
     return status;
 }
@@ -91,9 +90,6 @@ celix_status_t bundleActivator_stop(void * userData, bundle_context_pt context)
 
 celix_status_t bundleActivator_destroy(void * userData, bundle_context_pt context) {
     bundle_instance_pt bi = (bundle_instance_pt) userData;
-    if (bi != NULL) {
-        free(bi->dmCommand);
-    }
     free(bi);
     return CELIX_SUCCESS;
 }

http://git-wip-us.apache.org/repos/asf/celix/blob/7d379221/dependency_manager/private/src/dm_shell_list_command.c
----------------------------------------------------------------------
diff --git a/dependency_manager/private/src/dm_shell_list_command.c b/dependency_manager/private/src/dm_shell_list_command.c
index c6fe68c..1600710 100644
--- a/dependency_manager/private/src/dm_shell_list_command.c
+++ b/dependency_manager/private/src/dm_shell_list_command.c
@@ -26,6 +26,7 @@
 #include <stdlib.h>
 #include <string.h>
 #include <dm_dependency_manager.h>
+#include <dm_shell_list_command.h>
 #include "dm_info.h"
 #include "service_reference.h"
 #include "array_list.h"
@@ -39,28 +40,25 @@ static const char * const WARNING_COLOR = "\033[93m";
 static const char * const NOK_COLOR = "\033[91m";
 static const char * const END_COLOR = "\033[m";
 
-void dmListCommand_execute(bundle_context_pt context, char * line, FILE *out, FILE *err) {
+void dmListCommand_execute(dm_command_handle_t* handle, char * line, FILE *out, FILE *err) {
+
     array_list_pt servRefs = NULL;
     int i;
-    bundleContext_getServiceReferences(context, DM_INFO_SERVICE_NAME ,NULL, &servRefs);
+    bundleContext_getServiceReferences(handle->context, DM_INFO_SERVICE_NAME ,NULL, &servRefs);
 
     if(servRefs==NULL){
 	fprintf(out, "Invalid dm_info ServiceReferences List\n");
 	return;
     }
 
-    char *term = getenv("TERM");
-    bool colors = false;
-    if (strcmp("xterm-256color", term) == 0) {
-        colors = true;
-    }
+    bool colors = handle->useColors;
 
     for(i = 0; i < arrayList_size(servRefs); i++) {
         dm_dependency_manager_info_pt info = NULL;
         dm_info_service_pt infoServ = NULL;
         service_reference_pt servRef = NULL;
         servRef = arrayList_get(servRefs, i);
-        bundleContext_getService(context,  servRef, (void**)&infoServ);
+        bundleContext_getService(handle->context,  servRef, (void**)&infoServ);
         infoServ->getInfo(infoServ->handle, &info);
 
         int cmpCnt;
@@ -117,8 +115,8 @@ void dmListCommand_execute(bundle_context_pt context, char * line, FILE *out, FI
 
             infoServ->destroyInfo(infoServ->handle, info);
 
-		bundleContext_ungetService(context,servRef,NULL);
-		bundleContext_ungetServiceReference(context,servRef);
+		bundleContext_ungetService(handle->context, servRef, NULL);
+		bundleContext_ungetServiceReference(handle->context, servRef);
 
     }
 

http://git-wip-us.apache.org/repos/asf/celix/blob/7d379221/dependency_manager/readme.md
----------------------------------------------------------------------
diff --git a/dependency_manager/readme.md b/dependency_manager/readme.md
index 1289c46..864fc3a 100644
--- a/dependency_manager/readme.md
+++ b/dependency_manager/readme.md
@@ -113,6 +113,19 @@ celix_status_t dm_destroy(void * userData, bundle_context_pt context, dm_depende
     return CELIX_SUCCESS;
 }  
 ```
+
+
+### Dependency Manager Shell support
+
+There is support for retrieving information of the dm components with
+use of the `dm` command. This command will print all known dm component,
+their state, provided interfaces and required interfaces.
+
+#### Dependency Manager Shell Config Options
+
+- DM_SHELL_USE_ANSI_COLORS - Wether to use ANSI colors when printing dm
+info. default is true.
+
 ### References
 
 For more information examples please see

http://git-wip-us.apache.org/repos/asf/celix/blob/7d379221/framework/public/include/service_tracker_customizer.h
----------------------------------------------------------------------
diff --git a/framework/public/include/service_tracker_customizer.h b/framework/public/include/service_tracker_customizer.h
index 660bbb4..19672d8 100644
--- a/framework/public/include/service_tracker_customizer.h
+++ b/framework/public/include/service_tracker_customizer.h
@@ -44,6 +44,8 @@ typedef celix_status_t (*modified_callback_pt)(void *handle, service_reference_p
 typedef celix_status_t (*removed_callback_pt)(void *handle, service_reference_pt reference, void *service);
 
 typedef struct serviceTrackerCustomizer *service_tracker_customizer_pt;
+typedef struct serviceTrackerCustomizer service_tracker_customizer_t;
+
 
 FRAMEWORK_EXPORT celix_status_t serviceTrackerCustomizer_create(void *handle,
 																adding_callback_pt addingFunction,

http://git-wip-us.apache.org/repos/asf/celix/blob/7d379221/shell_tui/README.md
----------------------------------------------------------------------
diff --git a/shell_tui/README.md b/shell_tui/README.md
index 4cdcda4..a637214 100644
--- a/shell_tui/README.md
+++ b/shell_tui/README.md
@@ -1,6 +1,12 @@
-## Shell TUI
+# Shell TUI
 
 The Celix Shell TUI implements a textual user interface for the Celix Shell.
 
-###### CMake option
+## CMake option
     BUILD_SHELL_TUI=ON
+
+## Config options
+
+- SHELL_USE_ANSI_CONTROL_SEQUENCES - Wether to use ANSI control
+sequences to support backspace, left, up, etc key commands in the
+shell tui. Default is true if a TERM environment is set else false.

http://git-wip-us.apache.org/repos/asf/celix/blob/7d379221/shell_tui/private/include/shell_tui.h
----------------------------------------------------------------------
diff --git a/shell_tui/private/include/shell_tui.h b/shell_tui/private/include/shell_tui.h
index 29f5eda..b561ff6 100644
--- a/shell_tui/private/include/shell_tui.h
+++ b/shell_tui/private/include/shell_tui.h
@@ -29,24 +29,16 @@
 
 #include <stdlib.h>
 
-#include "bundle_context.h"
 #include "celix_threads.h"
-#include "service_reference.h"
 #include "shell.h"
-#include "service_tracker.h"
 
-struct shellTuiActivator {
-    bundle_context_pt context;
-    shell_service_pt shell;
-    service_tracker_pt tracker;
-    bool running;
-    celix_thread_t runnable;
-    celix_thread_mutex_t mutex;
-};
+typedef struct shell_tui shell_tui_t ;
 
-typedef struct shellTuiActivator * shell_tui_activator_pt;
+shell_tui_t* shellTui_create(bool useAnsiControlSequences);
+celix_status_t shellTui_start(shell_tui_t* shellTui);
+celix_status_t shellTui_stop(shell_tui_t* shellTui);
+void shellTui_destroy(shell_tui_t* shellTui);
 
-celix_status_t shellTui_start(shell_tui_activator_pt activator);
-celix_status_t shellTui_stop(shell_tui_activator_pt activator);
+celix_status_t shellTui_setShell(shell_tui_t* shellTui, shell_service_t* svc);
 
 #endif /* SHELL_TUI_H_ */

http://git-wip-us.apache.org/repos/asf/celix/blob/7d379221/shell_tui/private/src/activator.c
----------------------------------------------------------------------
diff --git a/shell_tui/private/src/activator.c b/shell_tui/private/src/activator.c
index ec28088..f25dd5b 100644
--- a/shell_tui/private/src/activator.c
+++ b/shell_tui/private/src/activator.c
@@ -24,6 +24,7 @@
  *  \copyright	Apache License, Version 2.0
  */
 #include <stdlib.h>
+#include <string.h>
 
 #include "bundle_context.h"
 #include "bundle_activator.h"
@@ -32,36 +33,65 @@
 #include "shell_tui.h"
 #include "service_tracker.h"
 
+#define SHELL_USE_ANSI_CONTROL_SEQUENCES "SHELL_USE_ANSI_CONTROL_SEQUENCES"
+
+typedef struct shell_tui_activator {
+    shell_tui_t* shellTui;
+    service_tracker_pt tracker;
+    shell_service_t* currentSvc;
+    bool useAnsiControlSequences;
+} shell_tui_activator_t;
+
 
 static celix_status_t activator_addShellService(void *handle, service_reference_pt ref, void *svc) {
-    shell_tui_activator_pt act = (shell_tui_activator_pt) handle;
-    celixThreadMutex_lock(&act->mutex);
-    act->shell = svc;
-    celixThreadMutex_unlock(&act->mutex);
+    shell_tui_activator_t* act = (shell_tui_activator_t*) handle;
+    act->currentSvc = svc;
+    shellTui_setShell(act->shellTui, svc);
     return CELIX_SUCCESS;
 }
 
 static celix_status_t activator_removeShellService(void *handle, service_reference_pt ref, void *svc) {
-    shell_tui_activator_pt act = (shell_tui_activator_pt) handle;
-    celixThreadMutex_lock(&act->mutex);
-    if (act->shell == svc) {
-        act->shell = NULL;
+    shell_tui_activator_t* act = (shell_tui_activator_t*) handle;
+    if (act->currentSvc == svc) {
+        act->currentSvc = NULL;
+        shellTui_setShell(act->shellTui, NULL);
     }
-    celixThreadMutex_unlock(&act->mutex);
     return CELIX_SUCCESS;
 }
 
 celix_status_t bundleActivator_create(bundle_context_pt context, void **userData) {
 	celix_status_t status = CELIX_SUCCESS;
 
-	shell_tui_activator_pt activator = (shell_tui_activator_pt) calloc(1, sizeof(*activator));
+    shell_tui_activator_t* activator = calloc(1, sizeof(*activator));
+
+	if (activator != NULL) {
+        bool useCommands;
+        const char* config = NULL;
+        bundleContext_getProperty(context, SHELL_USE_ANSI_CONTROL_SEQUENCES, &config);
+        if (config != NULL) {
+            useCommands = strncmp("true", config, 5) == 0;
+        } else {
+            char *term = getenv("TERM");
+            useCommands = term != NULL;
+        }
 
-	if (activator) {
-		activator->shell = NULL;
-        celixThreadMutex_create(&activator->mutex, NULL);
-		(*userData) = activator;
+        activator->shellTui = shellTui_create(useCommands);
+
+        service_tracker_customizer_t* cust = NULL;
+        serviceTrackerCustomizer_create(activator, NULL, activator_addShellService, NULL, activator_removeShellService, &cust);
+        serviceTracker_create(context, OSGI_SHELL_SERVICE_NAME, cust, &activator->tracker);
 	}
-	else {
+
+    if (activator != NULL && activator->shellTui != NULL) {
+        (*userData) = activator;
+    } else {
+        if (activator != NULL) {
+            shellTui_destroy(activator->shellTui);
+            if (activator->tracker != NULL) {
+                serviceTracker_destroy(activator->tracker);
+            }
+        }
+        free(activator);
 		status = CELIX_ENOMEM;
 	}
 
@@ -71,39 +101,33 @@ celix_status_t bundleActivator_create(bundle_context_pt context, void **userData
 celix_status_t bundleActivator_start(void * userData, bundle_context_pt context) {
 	celix_status_t status = CELIX_SUCCESS;
 
-	shell_tui_activator_pt act = (shell_tui_activator_pt) userData;
+    shell_tui_activator_t* act = (shell_tui_activator_t*) userData;
 
-    service_tracker_customizer_pt cust = NULL;
-    serviceTrackerCustomizer_create(userData, NULL, activator_addShellService, NULL, activator_removeShellService, &cust);
-    serviceTracker_create(context, (char *) OSGI_SHELL_SERVICE_NAME, cust, &act->tracker);
+    act->currentSvc = NULL;
     serviceTracker_open(act->tracker);
-
-    shellTui_start(act);
+    shellTui_start(act->shellTui);
 
 	return status;
 }
 
 celix_status_t bundleActivator_stop(void * userData, bundle_context_pt context) {
 	celix_status_t status = CELIX_SUCCESS;
-	shell_tui_activator_pt act = (shell_tui_activator_pt) userData;
+    shell_tui_activator_t* act = (shell_tui_activator_t*) userData;
 
     if (act != NULL) {
-        shellTui_stop(act);
-        if (act->tracker != NULL) {
-            serviceTracker_close(act->tracker);
-        }
+        serviceTracker_close(act->tracker);
+        shellTui_stop(act->shellTui);
     }
 
 	return status;
 }
 
 celix_status_t bundleActivator_destroy(void * userData, bundle_context_pt context) {
-	shell_tui_activator_pt activator = (shell_tui_activator_pt) userData;
+    shell_tui_activator_t* act = (shell_tui_activator_t*) userData;
 
-    if (activator->tracker != NULL) {
-        serviceTracker_destroy(activator->tracker);
-    }
-	free(activator);
+    shellTui_destroy(act->shellTui);
+    serviceTracker_destroy(act->tracker);
+	free(act);
 
 	return CELIX_SUCCESS;
 }

http://git-wip-us.apache.org/repos/asf/celix/blob/7d379221/shell_tui/private/src/history.c
----------------------------------------------------------------------
diff --git a/shell_tui/private/src/history.c b/shell_tui/private/src/history.c
index ee77f2e..e58c502 100644
--- a/shell_tui/private/src/history.c
+++ b/shell_tui/private/src/history.c
@@ -16,13 +16,6 @@
  *specific language governing permissions and limitations
  *under the License.
  */
-/*
- * activator.c
- *
- *  \date       Jan 15, 2016
- *  \author    	<a href="mailto:dev@celix.apache.org">Apache Celix Project Team</a>
- *  \copyright	Apache License, Version 2.0
- */
 
 #include "history.h"
 #include <stdlib.h>

http://git-wip-us.apache.org/repos/asf/celix/blob/7d379221/shell_tui/private/src/shell_tui.c
----------------------------------------------------------------------
diff --git a/shell_tui/private/src/shell_tui.c b/shell_tui/private/src/shell_tui.c
index 7c2fa3b..f421e6e 100644
--- a/shell_tui/private/src/shell_tui.c
+++ b/shell_tui/private/src/shell_tui.c
@@ -39,6 +39,7 @@
 #include "utils.h"
 #include <signal.h>
 #include <unistd.h>
+#include <fcntl.h>
 #include "history.h"
 
 #define LINE_SIZE 256
@@ -56,6 +57,25 @@
 #define KEY_DEL1		'3'
 #define KEY_DEL2		'~'
 
+struct shell_tui {
+    celix_thread_mutex_t mutex; //protects shell
+    shell_service_t* shell;
+    celix_thread_t thread;
+
+    int readPipeFd;
+    int writePipeFd;
+
+    bool useAnsiControlSequences;
+};
+
+typedef struct shell_context {
+    char in[LINE_SIZE];
+    char buffer[LINE_SIZE];
+    char dline[LINE_SIZE];
+    int pos;
+    history_t* hist;
+} shell_context_t;
+
 // static function declarations
 static void remove_newlines(char* line);
 static void clearLine();
@@ -63,161 +83,254 @@ static void cursorLeft(int n);
 static void writeLine(const char*line, int pos);
 static int autoComplete(shell_service_pt shellSvc, char *in, int cursorPos, size_t maxLen);
 static void* shellTui_runnable(void *data);
+static void shellTui_parseInputForControl(shell_tui_t* shellTui, shell_context_t* ctx);
+static void shellTui_parseInput(shell_tui_t* shellTui, shell_context_t* ctx);
+static void writePrompt(void);
 
+shell_tui_t* shellTui_create(bool useAnsiControlSequences) {
+    shell_tui_t* result = calloc(1, sizeof(*result));
+    if (result != NULL) {
+        result->useAnsiControlSequences = useAnsiControlSequences;
+        celixThreadMutex_create(&result->mutex, NULL);
+    }
+    return result;
+}
 
-celix_status_t shellTui_start(shell_tui_activator_pt activator) {
-
+celix_status_t shellTui_start(shell_tui_t* shellTui) {
     celix_status_t status = CELIX_SUCCESS;
 
-    activator->running = true;
-    celixThread_create(&activator->runnable, NULL, shellTui_runnable, activator);
+    int fds[2];
+    int rc  = pipe(fds);
+    if (rc == 0) {
+        shellTui->readPipeFd = fds[0];
+        shellTui->writePipeFd = fds[1];
+        fcntl(shellTui->writePipeFd, F_SETFL, O_NONBLOCK);
+        celixThread_create(&shellTui->thread, NULL, shellTui_runnable, shellTui);
+    } else {
+        fprintf(stderr, "Cannot create pipe");
+        status = CELIX_BUNDLE_EXCEPTION;
+    }
 
     return status;
 }
 
-celix_status_t shellTui_stop(shell_tui_activator_pt act) {
+celix_status_t shellTui_stop(shell_tui_t* shellTui) {
     celix_status_t status = CELIX_SUCCESS;
-    act->running = false;
-    celixThread_kill(act->runnable, SIGUSR1);
-    celixThread_join(act->runnable, NULL);
+    write(shellTui->writePipeFd, "\0", 1); //trigger select to stop
+    celixThread_join(shellTui->thread, NULL);
+    close(shellTui->writePipeFd);
+    close(shellTui->readPipeFd);
     return status;
 }
 
+void shellTui_destroy(shell_tui_t* shellTui) {
+    if (shellTui == NULL) return;
+
+    celixThreadMutex_destroy(&shellTui->mutex);
+    free(shellTui);
+}
 
+celix_status_t shellTui_setShell(shell_tui_t* shellTui, shell_service_t* svc) {
+    celixThreadMutex_lock(&shellTui->mutex);
+    shellTui->shell = svc;
+    celixThreadMutex_unlock(&shellTui->mutex);
+    return CELIX_SUCCESS;
+}
 
 static void* shellTui_runnable(void *data) {
-    shell_tui_activator_pt act = (shell_tui_activator_pt) data;
+    shell_tui_t* shellTui = (shell_tui_t*) data;
 
-    char in[LINE_SIZE] = "";
-    char buffer[LINE_SIZE];
-    int pos = 0;
-    char dline[LINE_SIZE];
-    fd_set rfds;
-    struct timeval tv;
+    //setup shell context
+    shell_context_t ctx;
+    memset(&ctx, 0, sizeof(ctx));
+    ctx.hist = historyCreate();
 
+    //setup term
     struct termios term_org, term_new;
-    tcgetattr(STDIN_FILENO, &term_org);
-    term_new = term_org;
-    term_new.c_lflag &= ~( ICANON | ECHO);
-    tcsetattr(STDIN_FILENO,  TCSANOW, &term_new);
+    if (shellTui->useAnsiControlSequences) {
+        tcgetattr(STDIN_FILENO, &term_org);
+        term_new = term_org;
+        term_new.c_lflag &= ~(ICANON | ECHO);
+        tcsetattr(STDIN_FILENO, TCSANOW, &term_new);
+    }
 
-    history_t *hist = historyCreate();
+    //setup file descriptors
+    fd_set rfds;
+    int nfds = shellTui->writePipeFd > STDIN_FILENO ? (shellTui->writePipeFd +1) : (STDIN_FILENO + 1);
 
-    while (act->running) {
-        char * line = NULL;
-        writeLine(in, pos);
+    for (;;) {
+        if (shellTui->useAnsiControlSequences) {
+            writeLine(ctx.in, ctx.pos);
+        } else {
+            writePrompt();
+        }
         FD_ZERO(&rfds);
         FD_SET(STDIN_FILENO, &rfds);
+        FD_SET(shellTui->readPipeFd, &rfds);
 
-        tv.tv_sec = 1;
-        tv.tv_usec = 0;
-
-        if (select(1, &rfds, NULL, NULL, &tv) > 0) {
-        	int nr_chars = read(STDIN_FILENO, buffer, LINE_SIZE-pos);
-            for(int bufpos = 0; bufpos < nr_chars; bufpos++) {
-                if (buffer[bufpos] == KEY_ESC1 && buffer[bufpos+1] == KEY_ESC2) {
-                    switch (buffer[bufpos+2]) {
-                        case KEY_UP:
-                            if(historySize(hist) > 0) {
-                                strncpy(in, historyGetPrevLine(hist), LINE_SIZE);
-                                pos = strlen(in);
-                                writeLine(in, pos);
-                            }
-                            break;
-                        case KEY_DOWN:
-                            if(historySize(hist) > 0) {
-                                strncpy(in, historyGetNextLine(hist), LINE_SIZE);
-                                pos = strlen(in);
-                                writeLine(in, pos);
-                            }
-                            break;
-                        case KEY_RIGHT:
-                            if (pos < strlen(in)) {
-                        		pos++;
-                        	}
-                    		writeLine(in, pos);
-                        	break;
-                        case KEY_LEFT:
-                        	if (pos > 0) {
-                            	pos--;
-                            }
-                    		writeLine(in, pos);
-                            break;
-                        case KEY_DEL1:
-                        	if(buffer[bufpos+3] == KEY_DEL2) {
-                                bufpos++; // delete cmd takes 4 chars
-                                int len = strlen(in);
-                                if (pos < len) {
-                                	for (int i = pos; i <= len; i++) {
-                                		in[i] = in[i + 1];
-                                	}
-                                }
-                                writeLine(in, pos);
-                        	}
-                        	break;
-                        default:
-                        	// Unsupported char, do nothing
-                        	break;
-                    }
-                    bufpos+=2;
-                    continue;
-                } else if(buffer[bufpos] == KEY_BACKSPACE) { // backspace
-                	if(pos > 0) {
-                		int len = strlen(in);
-                		for(int i = pos-1; i <= len; i++) {
-                			in[i] = in[i+1];
-                		}
-                		pos--;
-                	}
-            		writeLine(in, pos);
-            		continue;
-                } else if(buffer[bufpos] == KEY_TAB) {
-                	pos = autoComplete(act->shell, in, pos, LINE_SIZE);
-            		continue;
-                } else if(buffer[bufpos] != KEY_ENTER) { //text
-                	if(in[pos] == '\0') {
-                    	in[pos+1] = '\0';
-                	}
-                	in[pos] = buffer[bufpos];
-                    pos++;
-            		writeLine(in, pos);
-                	fflush(stdout);
-                	continue;
+        if (select(nfds, &rfds, NULL, NULL, NULL) > 0) {
+            if (FD_ISSET(shellTui->readPipeFd, &rfds)) {
+                break; //something is written to the pipe -> exit thread
+            } else if (FD_ISSET(STDIN_FILENO, &rfds)) {
+                if (shellTui->useAnsiControlSequences) {
+                    shellTui_parseInputForControl(shellTui, &ctx);
+                } else {
+                    shellTui_parseInput(shellTui, &ctx);
                 }
-        		writeLine(in, pos);
-                write(STDOUT_FILENO, "\n", 1);
-                remove_newlines(in);
-                history_addLine(hist, in);
+            }
+        }
+    }
+    tcsetattr(STDIN_FILENO,  TCSANOW, &term_org); //TODO or after SIGINT
+    historyDestroy(ctx.hist);
+
+    return NULL;
+}
 
-                memset(dline, 0, LINE_SIZE);
-                strncpy(dline, in, LINE_SIZE);
+static void shellTui_parseInput(shell_tui_t* shellTui, shell_context_t* ctx) {
+    char* buffer = ctx->buffer;
+    char* in = ctx->in;
+    int pos = ctx->pos;
 
-                pos = 0;
-                in[pos] = '\0';
+    char* line = NULL;
 
-                line = utils_stringTrim(dline);
-                if ((strlen(line) == 0) || (act->shell == NULL)) {
-                    continue;
-                }
-                historyLineReset(hist);
-                celixThreadMutex_lock(&act->mutex);
-                if (act->shell != NULL) {
-                    act->shell->executeCommand(act->shell->shell, line, stdout, stderr);
-                    pos = 0;
-                    nr_chars = 0;
-                    celixThreadMutex_unlock(&act->mutex);
+
+    int nr_chars = read(STDIN_FILENO, buffer, LINE_SIZE-pos-1);
+    for(int bufpos = 0; bufpos < nr_chars; bufpos++) {
+        if (buffer[bufpos] == KEY_ENTER) { //end of line -> forward command
+            line = utils_stringTrim(in);
+            celixThreadMutex_lock(&shellTui->mutex);
+            if (shellTui->shell != NULL) {
+                printf("Providing command '%s' from in '%s'\n", line, in);
+                shellTui->shell->executeCommand(shellTui->shell->shell, line, stdout, stderr);
+            } else {
+                fprintf(stderr, "Shell service not available\n");
+            }
+            celixThreadMutex_unlock(&shellTui->mutex);
+            pos = 0;
+            in[pos] = '\0';
+        } else { //text
+            in[pos] = buffer[bufpos];
+            in[pos+1] = '\0';
+            pos++;
+            continue;
+        }
+    } // for
+    ctx->pos = pos;
+}
+
+static void shellTui_parseInputForControl(shell_tui_t* shellTui, shell_context_t* ctx) {
+    char* buffer = ctx->buffer;
+    char* in = ctx->in;
+    char* dline = ctx->dline;
+    history_t* hist = ctx->hist;
+    int pos = ctx->pos;
+
+    char* line = NULL;
+
+    int nr_chars = read(STDIN_FILENO, buffer, LINE_SIZE-pos-1);
+    for(int bufpos = 0; bufpos < nr_chars; bufpos++) {
+        if (buffer[bufpos] == KEY_ESC1 && buffer[bufpos+1] == KEY_ESC2) {
+            switch (buffer[bufpos+2]) {
+                case KEY_UP:
+                    if(historySize(hist) > 0) {
+                        strncpy(in, historyGetPrevLine(hist), LINE_SIZE);
+                        pos = strlen(in);
+                        writeLine(in, pos);
+                    }
                     break;
-                } else {
-                    fprintf(stderr, "Shell service not available\n");
+                case KEY_DOWN:
+                    if(historySize(hist) > 0) {
+                        strncpy(in, historyGetNextLine(hist), LINE_SIZE);
+                        pos = strlen(in);
+                        writeLine(in, pos);
+                    }
+                    break;
+                case KEY_RIGHT:
+                    if (pos < strlen(in)) {
+                        pos++;
+                    }
+                    writeLine(in, pos);
+                    break;
+                case KEY_LEFT:
+                    if (pos > 0) {
+                        pos--;
+                    }
+                    writeLine(in, pos);
+                    break;
+                case KEY_DEL1:
+                    if(buffer[bufpos+3] == KEY_DEL2) {
+                        bufpos++; // delete cmd takes 4 chars
+                        int len = strlen(in);
+                        if (pos < len) {
+                            for (int i = pos; i <= len; i++) {
+                                in[i] = in[i + 1];
+                            }
+                        }
+                        writeLine(in, pos);
+                    }
+                    break;
+                default:
+                    // Unsupported char, do nothing
+                    break;
+            }
+            bufpos+=2;
+            continue;
+        } else if (buffer[bufpos] == KEY_BACKSPACE) { // backspace
+            if(pos > 0) {
+                int len = strlen(in);
+                for(int i = pos-1; i <= len; i++) {
+                    in[i] = in[i+1];
                 }
-                celixThreadMutex_unlock(&act->mutex);
-            } // for
+                pos--;
+            }
+            writeLine(in, pos);
+            continue;
+        } else if(buffer[bufpos] == KEY_TAB) {
+            celixThreadMutex_lock(&shellTui->mutex);
+            if (shellTui != NULL) {
+                pos = autoComplete(shellTui->shell, in, pos, LINE_SIZE);
+            }
+            celixThreadMutex_unlock(&shellTui->mutex);
+            continue;
+        } else if (buffer[bufpos] != KEY_ENTER) { //not end of line -> text
+            if (in[pos] == '\0') {
+                in[pos+1] = '\0';
+            }
+            in[pos] = buffer[bufpos];
+            pos++;
+            writeLine(in, pos);
+            fflush(stdout);
+            continue;
         }
-    }
-    tcsetattr(STDIN_FILENO,  TCSANOW, &term_org);
-    historyDestroy(hist);
 
-    return NULL;
+        //parse enter
+        writeLine(in, pos);
+        write(STDOUT_FILENO, "\n", 1);
+        remove_newlines(in);
+        history_addLine(hist, in);
+
+        memset(dline, 0, LINE_SIZE);
+        strncpy(dline, in, LINE_SIZE);
+
+        pos = 0;
+        in[pos] = '\0';
+
+        line = utils_stringTrim(dline);
+        if ((strlen(line) == 0)) {
+            continue;
+        }
+        historyLineReset(hist);
+        celixThreadMutex_lock(&shellTui->mutex);
+        if (shellTui->shell != NULL) {
+            shellTui->shell->executeCommand(shellTui->shell->shell, line, stdout, stderr);
+            pos = 0;
+            nr_chars = 0;
+        } else {
+            fprintf(stderr, "Shell service not available\n");
+        }
+        celixThreadMutex_unlock(&shellTui->mutex);
+    } // for
+    ctx->pos = pos;
 }
 
 static void remove_newlines(char* line) {
@@ -242,14 +355,18 @@ static void cursorLeft(int n) {
 	}
 }
 
-static void writeLine(const char*line, int pos) {
+static void writePrompt(void) {
+    write(STDIN_FILENO, PROMPT, strlen(PROMPT));
+}
+
+static void writeLine(const char* line, int pos) {
     clearLine();
     write(STDOUT_FILENO, PROMPT, strlen(PROMPT));
     write(STDOUT_FILENO, line, strlen(line));
 	cursorLeft(strlen(line)-pos);
 }
 
-static int autoComplete(shell_service_pt shellSvc, char *in, int cursorPos, size_t maxLen) {
+static int autoComplete(shell_service_t* shellSvc, char *in, int cursorPos, size_t maxLen) {
 	array_list_pt commandList = NULL;
 	array_list_pt possibleCmdList = NULL;
 	shellSvc->getCommands(shellSvc->shell, &commandList);