Index: uspace/lib/clui/include/nchoice.h
===================================================================
--- uspace/lib/clui/include/nchoice.h	(revision 017ffcee78370959909c2b932d4a0e2b1c7c3c55)
+++ uspace/lib/clui/include/nchoice.h	(revision 017ffcee78370959909c2b932d4a0e2b1c7c3c55)
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2015 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup libclui
+ * @{
+ */
+/**
+ * @file Numerical choice
+ */
+
+#ifndef LIBCLUI_NCHOICE_H_
+#define LIBCLUI_NCHOICE_H_
+
+#include <adt/list.h>
+#include <tinput.h>
+
+typedef enum {
+	/** This is the default option */
+	ncf_default = 1
+} nchoice_flag_t;
+
+typedef struct {
+	/** Link to nchoice_t.opts */
+	link_t lchoice;
+	/** Option text */
+	char *text;
+	/** User argument */
+	void *arg;
+} nchoice_opt_t;
+
+typedef struct {
+	/** Prompt text */
+	char *prompt;
+	/** Options */
+	list_t opts; /* of nchoice_opt_t */
+	/** Text input */
+	tinput_t *tinput;
+	/** Default option */
+	nchoice_opt_t *def_opt;
+} nchoice_t;
+
+extern errno_t nchoice_create(nchoice_t **);
+extern void nchoice_destroy(nchoice_t *);
+extern errno_t nchoice_set_prompt(nchoice_t *, const char *);
+extern errno_t nchoice_add(nchoice_t *, const char *, void *, nchoice_flag_t);
+extern errno_t nchoice_get(nchoice_t *, void **);
+
+#endif
+
+/** @}
+ */
Index: uspace/lib/clui/include/tinput.h
===================================================================
--- uspace/lib/clui/include/tinput.h	(revision 017ffcee78370959909c2b932d4a0e2b1c7c3c55)
+++ uspace/lib/clui/include/tinput.h	(revision 017ffcee78370959909c2b932d4a0e2b1c7c3c55)
@@ -0,0 +1,165 @@
+/*
+ * Copyright (c) 2011 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup libclui
+ * @{
+ */
+/**
+ * @file
+ */
+
+#ifndef LIBCLUI_TINPUT_H_
+#define LIBCLUI_TINPUT_H_
+
+#include <inttypes.h>
+#include <io/console.h>
+#include <stdio.h>
+
+#define HISTORY_LEN     10
+#define INPUT_MAX_SIZE  1024
+
+/** Begin enumeration of text completions.
+ *
+ * When user requests text completion, tinput will call this function to start
+ * text completion operation. @a *cstart should be set to the position
+ * (character index) of the first character of the 'word' that is being
+ * completed. The resulting text is obtained by replacing the range of text
+ * starting at @a *cstart and ending at @a pos with the completion text.
+ *
+ * The function can pass information to the get_next and fini functions
+ * via @a state. The init function allocates the state object and stores
+ * a pointer to it to @a *state. The fini function destroys the state object.
+ *
+ * @param text		Current contents of edit buffer (null-terminated).
+ * @param pos		Current caret position.
+ * @param cstart	Output, position in text where completion begins from.
+ * @param state		Output, pointer to a client state object.
+ *
+ * @return		EOK on success, error code on failure.
+ */
+typedef errno_t (*tinput_compl_init_fn)(char32_t *text, size_t pos, size_t *cstart,
+    void **state);
+
+/** Obtain one text completion alternative.
+ *
+ * Upon success the function sets @a *compl to point to a string, the
+ * completion text. The caller (Tinput) should not modify or free the text.
+ * The pointer is only valid until the next invocation of any completion
+ * function.
+ *
+ * @param state		Pointer to state object created by the init funtion.
+ * @param compl		Output, the completion text, ownership retained.
+ *
+ * @return		EOK on success, error code on failure.
+ */
+typedef errno_t (*tinput_compl_get_next_fn)(void *state, char **compl);
+
+/** Finish enumeration of text completions.
+ *
+ * The function must deallocate any state information allocated by the init
+ * function or temporary data allocated by the get_next function.
+ *
+ * @param state		Pointer to state object created by the init funtion.
+ */
+typedef void (*tinput_compl_fini_fn)(void *state);
+
+/** Text completion ops. */
+typedef struct {
+	tinput_compl_init_fn init;
+	tinput_compl_get_next_fn get_next;
+	tinput_compl_fini_fn fini;
+} tinput_compl_ops_t;
+
+/** Text input field (command line).
+ *
+ * Applications should treat this structure as opaque.
+ */
+typedef struct {
+	/** Console */
+	console_ctrl_t *console;
+
+	/** Prompt string */
+	char *prompt;
+
+	/** Completion ops. */
+	tinput_compl_ops_t *compl_ops;
+
+	/** Buffer holding text currently being edited */
+	char32_t buffer[INPUT_MAX_SIZE + 1];
+
+	/** Linear position on screen where the prompt starts */
+	unsigned prompt_coord;
+	/** Linear position on screen where the text field starts */
+	unsigned text_coord;
+
+	/** Screen dimensions */
+	sysarg_t con_cols;
+	sysarg_t con_rows;
+
+	/** Number of characters in @c buffer */
+	size_t nc;
+
+	/** Caret position within buffer */
+	size_t pos;
+
+	/** Selection mark position within buffer */
+	size_t sel_start;
+
+	/** History (dynamically allocated strings) */
+	char *history[HISTORY_LEN + 1];
+
+	/** Number of entries in @c history, not counting [0] */
+	size_t hnum;
+
+	/** Current position in history */
+	size_t hpos;
+
+	/** @c true if finished with this line (return to caller) */
+	bool done;
+
+	/** @c true if user requested to abort interactive loop */
+	bool exit_clui;
+
+	/** @c true if left shift key is currently held */
+	bool lshift_held;
+
+	/** @c true if right shift key is currently held */
+	bool rshift_held;
+} tinput_t;
+
+extern tinput_t *tinput_new(void);
+extern errno_t tinput_set_prompt(tinput_t *, const char *);
+extern void tinput_set_compl_ops(tinput_t *, tinput_compl_ops_t *);
+extern void tinput_destroy(tinput_t *);
+extern errno_t tinput_read(tinput_t *, char **);
+extern errno_t tinput_read_i(tinput_t *, const char *, char **);
+
+#endif
+
+/** @}
+ */
Index: uspace/lib/clui/meson.build
===================================================================
--- uspace/lib/clui/meson.build	(revision 00e62883ce36dafecb81ee65875c0b6a4529130b)
+++ uspace/lib/clui/meson.build	(revision 017ffcee78370959909c2b932d4a0e2b1c7c3c55)
@@ -29,5 +29,5 @@
 deps = [ 'clipboard', 'console' ]
 src = files(
-	'nchoice.c',
-	'tinput.c',
+	'src/nchoice.c',
+	'src/tinput.c',
 )
Index: uspace/lib/clui/nchoice.c
===================================================================
--- uspace/lib/clui/nchoice.c	(revision 00e62883ce36dafecb81ee65875c0b6a4529130b)
+++ 	(revision )
@@ -1,200 +1,0 @@
-/*
- * Copyright (c) 2015 Jiri Svoboda
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistributions of source code must retain the above copyright
- *   notice, this list of conditions and the following disclaimer.
- * - Redistributions in binary form must reproduce the above copyright
- *   notice, this list of conditions and the following disclaimer in the
- *   documentation and/or other materials provided with the distribution.
- * - The name of the author may not be used to endorse or promote products
- *   derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-/** @addtogroup libclui
- * @{
- */
-/**
- * @file Numerical choice
- */
-
-#include <errno.h>
-#include <nchoice.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <str.h>
-#include <tinput.h>
-
-/** Create numerical choice
- *
- */
-errno_t nchoice_create(nchoice_t **rchoice)
-{
-	nchoice_t *choice = NULL;
-	errno_t rc;
-
-	choice = calloc(1, sizeof(nchoice_t));
-	if (choice == NULL)
-		goto error;
-
-	list_initialize(&choice->opts);
-
-	choice->tinput = tinput_new();
-	if (choice->tinput == NULL)
-		goto error;
-
-	rc = tinput_set_prompt(choice->tinput, "Choice> ");
-	if (rc != EOK) {
-		assert(rc == ENOMEM);
-		goto error;
-	}
-
-	*rchoice = choice;
-	return EOK;
-error:
-	nchoice_destroy(choice);
-	return ENOMEM;
-}
-
-/** Destroy numerical choice */
-void nchoice_destroy(nchoice_t *choice)
-{
-	if (choice == NULL)
-		return;
-
-	tinput_destroy(choice->tinput);
-	free(choice);
-}
-
-/** Set numerica choice prompt text */
-errno_t nchoice_set_prompt(nchoice_t *choice, const char *prompt)
-{
-	char *pstr;
-
-	pstr = str_dup(prompt);
-	if (pstr == NULL)
-		return ENOMEM;
-
-	free(choice->prompt);
-	choice->prompt = pstr;
-	return EOK;
-}
-
-/** Add option to numerical choice */
-errno_t nchoice_add(nchoice_t *choice, const char *opttext, void *arg,
-    nchoice_flag_t flags)
-{
-	nchoice_opt_t *opt;
-	char *ptext;
-
-	opt = calloc(1, sizeof(nchoice_opt_t));
-	if (opt == NULL)
-		return ENOMEM;
-
-	ptext = str_dup(opttext);
-	if (ptext == NULL) {
-		free(opt);
-		return ENOMEM;
-	}
-
-	opt->text = ptext;
-	opt->arg = arg;
-	list_append(&opt->lchoice, &choice->opts);
-
-	if ((flags & ncf_default) != 0) {
-		/* Set this option as the default */
-		assert(choice->def_opt == NULL);
-
-		choice->def_opt = opt;
-	}
-
-	return EOK;
-}
-
-/** Get numerical choice from user */
-errno_t nchoice_get(nchoice_t *choice, void **rarg)
-{
-	int i;
-	errno_t rc;
-	int ret;
-	char *str;
-	unsigned long c;
-	char *eptr;
-	char *istr;
-	int def_i;
-
-again:
-	printf("%s\n", choice->prompt);
-
-	def_i = 0;
-	i = 1;
-	list_foreach(choice->opts, lchoice, nchoice_opt_t, opt) {
-		printf("%d: %s%s\n", i, opt->text, opt == choice->def_opt ?
-		    " [default]" : "");
-		if (opt == choice->def_opt)
-			def_i = i;
-		++i;
-	}
-
-	if (def_i > 0) {
-		ret = asprintf(&istr, "%d", def_i);
-		if (ret < 0)
-			return ENOMEM;
-	} else {
-		istr = str_dup("");
-		if (istr == NULL)
-			return ENOMEM;
-	}
-
-	rc = tinput_read_i(choice->tinput, istr, &str);
-	free(istr);
-
-	if (rc != EOK) {
-		assert(rc == EIO || rc == ENOENT);
-
-		if (rc == ENOENT) {
-			return ENOENT;
-		} else {
-			/* rc == EIO */
-			return EIO;
-		}
-	}
-
-	c = strtoul(str, &eptr, 10);
-	if (*eptr != '\0' || c < 1 || c > (unsigned long)i - 1) {
-		printf("Invalid choice. Try again.\n");
-		free(str);
-		goto again;
-	}
-
-	free(str);
-
-	i = 1;
-	list_foreach(choice->opts, lchoice, nchoice_opt_t, opt) {
-		if ((unsigned long)i == c) {
-			*rarg = opt->arg;
-			return EOK;
-		}
-		++i;
-	}
-
-	assert(false);
-	return ENOENT;
-}
-
-/** @}
- */
Index: uspace/lib/clui/nchoice.h
===================================================================
--- uspace/lib/clui/nchoice.h	(revision 00e62883ce36dafecb81ee65875c0b6a4529130b)
+++ 	(revision )
@@ -1,76 +1,0 @@
-/*
- * Copyright (c) 2015 Jiri Svoboda
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistributions of source code must retain the above copyright
- *   notice, this list of conditions and the following disclaimer.
- * - Redistributions in binary form must reproduce the above copyright
- *   notice, this list of conditions and the following disclaimer in the
- *   documentation and/or other materials provided with the distribution.
- * - The name of the author may not be used to endorse or promote products
- *   derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-/** @addtogroup libclui
- * @{
- */
-/**
- * @file Numerical choice
- */
-
-#ifndef LIBCLUI_NCHOICE_H_
-#define LIBCLUI_NCHOICE_H_
-
-#include <adt/list.h>
-#include <tinput.h>
-
-typedef enum {
-	/** This is the default option */
-	ncf_default = 1
-} nchoice_flag_t;
-
-typedef struct {
-	/** Link to nchoice_t.opts */
-	link_t lchoice;
-	/** Option text */
-	char *text;
-	/** User argument */
-	void *arg;
-} nchoice_opt_t;
-
-typedef struct {
-	/** Prompt text */
-	char *prompt;
-	/** Options */
-	list_t opts; /* of nchoice_opt_t */
-	/** Text input */
-	tinput_t *tinput;
-	/** Default option */
-	nchoice_opt_t *def_opt;
-} nchoice_t;
-
-extern errno_t nchoice_create(nchoice_t **);
-extern void nchoice_destroy(nchoice_t *);
-extern errno_t nchoice_set_prompt(nchoice_t *, const char *);
-extern errno_t nchoice_add(nchoice_t *, const char *, void *, nchoice_flag_t);
-extern errno_t nchoice_get(nchoice_t *, void **);
-
-#endif
-
-/** @}
- */
Index: uspace/lib/clui/src/nchoice.c
===================================================================
--- uspace/lib/clui/src/nchoice.c	(revision 017ffcee78370959909c2b932d4a0e2b1c7c3c55)
+++ uspace/lib/clui/src/nchoice.c	(revision 017ffcee78370959909c2b932d4a0e2b1c7c3c55)
@@ -0,0 +1,200 @@
+/*
+ * Copyright (c) 2015 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+/** @addtogroup libclui
+ * @{
+ */
+/**
+ * @file Numerical choice
+ */
+
+#include <errno.h>
+#include <nchoice.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <str.h>
+#include <tinput.h>
+
+/** Create numerical choice
+ *
+ */
+errno_t nchoice_create(nchoice_t **rchoice)
+{
+	nchoice_t *choice = NULL;
+	errno_t rc;
+
+	choice = calloc(1, sizeof(nchoice_t));
+	if (choice == NULL)
+		goto error;
+
+	list_initialize(&choice->opts);
+
+	choice->tinput = tinput_new();
+	if (choice->tinput == NULL)
+		goto error;
+
+	rc = tinput_set_prompt(choice->tinput, "Choice> ");
+	if (rc != EOK) {
+		assert(rc == ENOMEM);
+		goto error;
+	}
+
+	*rchoice = choice;
+	return EOK;
+error:
+	nchoice_destroy(choice);
+	return ENOMEM;
+}
+
+/** Destroy numerical choice */
+void nchoice_destroy(nchoice_t *choice)
+{
+	if (choice == NULL)
+		return;
+
+	tinput_destroy(choice->tinput);
+	free(choice);
+}
+
+/** Set numerica choice prompt text */
+errno_t nchoice_set_prompt(nchoice_t *choice, const char *prompt)
+{
+	char *pstr;
+
+	pstr = str_dup(prompt);
+	if (pstr == NULL)
+		return ENOMEM;
+
+	free(choice->prompt);
+	choice->prompt = pstr;
+	return EOK;
+}
+
+/** Add option to numerical choice */
+errno_t nchoice_add(nchoice_t *choice, const char *opttext, void *arg,
+    nchoice_flag_t flags)
+{
+	nchoice_opt_t *opt;
+	char *ptext;
+
+	opt = calloc(1, sizeof(nchoice_opt_t));
+	if (opt == NULL)
+		return ENOMEM;
+
+	ptext = str_dup(opttext);
+	if (ptext == NULL) {
+		free(opt);
+		return ENOMEM;
+	}
+
+	opt->text = ptext;
+	opt->arg = arg;
+	list_append(&opt->lchoice, &choice->opts);
+
+	if ((flags & ncf_default) != 0) {
+		/* Set this option as the default */
+		assert(choice->def_opt == NULL);
+
+		choice->def_opt = opt;
+	}
+
+	return EOK;
+}
+
+/** Get numerical choice from user */
+errno_t nchoice_get(nchoice_t *choice, void **rarg)
+{
+	int i;
+	errno_t rc;
+	int ret;
+	char *str;
+	unsigned long c;
+	char *eptr;
+	char *istr;
+	int def_i;
+
+again:
+	printf("%s\n", choice->prompt);
+
+	def_i = 0;
+	i = 1;
+	list_foreach(choice->opts, lchoice, nchoice_opt_t, opt) {
+		printf("%d: %s%s\n", i, opt->text, opt == choice->def_opt ?
+		    " [default]" : "");
+		if (opt == choice->def_opt)
+			def_i = i;
+		++i;
+	}
+
+	if (def_i > 0) {
+		ret = asprintf(&istr, "%d", def_i);
+		if (ret < 0)
+			return ENOMEM;
+	} else {
+		istr = str_dup("");
+		if (istr == NULL)
+			return ENOMEM;
+	}
+
+	rc = tinput_read_i(choice->tinput, istr, &str);
+	free(istr);
+
+	if (rc != EOK) {
+		assert(rc == EIO || rc == ENOENT);
+
+		if (rc == ENOENT) {
+			return ENOENT;
+		} else {
+			/* rc == EIO */
+			return EIO;
+		}
+	}
+
+	c = strtoul(str, &eptr, 10);
+	if (*eptr != '\0' || c < 1 || c > (unsigned long)i - 1) {
+		printf("Invalid choice. Try again.\n");
+		free(str);
+		goto again;
+	}
+
+	free(str);
+
+	i = 1;
+	list_foreach(choice->opts, lchoice, nchoice_opt_t, opt) {
+		if ((unsigned long)i == c) {
+			*rarg = opt->arg;
+			return EOK;
+		}
+		++i;
+	}
+
+	assert(false);
+	return ENOENT;
+}
+
+/** @}
+ */
Index: uspace/lib/clui/src/tinput.c
===================================================================
--- uspace/lib/clui/src/tinput.c	(revision 017ffcee78370959909c2b932d4a0e2b1c7c3c55)
+++ uspace/lib/clui/src/tinput.c	(revision 017ffcee78370959909c2b932d4a0e2b1c7c3c55)
@@ -0,0 +1,1090 @@
+/*
+ * Copyright (c) 2011 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup libclui
+ * @{
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <str.h>
+#include <io/console.h>
+#include <io/keycode.h>
+#include <io/style.h>
+#include <io/color.h>
+#include <vfs/vfs.h>
+#include <clipboard.h>
+#include <macros.h>
+#include <errno.h>
+#include <assert.h>
+#include <stdbool.h>
+#include <tinput.h>
+
+#define LIN_TO_COL(ti, lpos) ((lpos) % ((ti)->con_cols))
+#define LIN_TO_ROW(ti, lpos) ((lpos) / ((ti)->con_cols))
+#define LIN_POS(ti, col, row) ((col) + (row) * (ti)->con_cols)
+
+/** Seek direction */
+typedef enum {
+	seek_backward = -1,
+	seek_forward = 1
+} seek_dir_t;
+
+static void tinput_update_origin(tinput_t *);
+static void tinput_init(tinput_t *);
+static void tinput_insert_string(tinput_t *, const char *);
+static void tinput_sel_get_bounds(tinput_t *, size_t *, size_t *);
+static bool tinput_sel_active(tinput_t *);
+static void tinput_sel_all(tinput_t *);
+static void tinput_sel_delete(tinput_t *);
+static void tinput_key_ctrl(tinput_t *, kbd_event_t *);
+static void tinput_key_shift(tinput_t *, kbd_event_t *);
+static void tinput_key_ctrl_shift(tinput_t *, kbd_event_t *);
+static void tinput_key_unmod(tinput_t *, kbd_event_t *);
+static void tinput_pre_seek(tinput_t *, bool);
+static void tinput_post_seek(tinput_t *, bool);
+
+static void tinput_console_set_lpos(tinput_t *ti, unsigned lpos)
+{
+	unsigned col = LIN_TO_COL(ti, lpos);
+	unsigned row = LIN_TO_ROW(ti, lpos);
+
+	assert(col < ti->con_cols);
+	assert(row < ti->con_rows);
+	console_set_pos(ti->console, col, row);
+}
+
+/** Create a new text input field. */
+tinput_t *tinput_new(void)
+{
+	tinput_t *ti;
+
+	ti = calloc(1, sizeof(tinput_t));
+	if (ti == NULL)
+		return NULL;
+
+	tinput_init(ti);
+	return ti;
+}
+
+/** Destroy text input field. */
+void tinput_destroy(tinput_t *ti)
+{
+	if (ti->prompt != NULL)
+		free(ti->prompt);
+	free(ti);
+}
+
+static void tinput_display_prompt(tinput_t *ti)
+{
+	tinput_console_set_lpos(ti, ti->prompt_coord);
+
+	console_set_style(ti->console, STYLE_EMPHASIS);
+	printf("%s", ti->prompt);
+	console_flush(ti->console);
+	console_set_style(ti->console, STYLE_NORMAL);
+}
+
+static void tinput_display_tail(tinput_t *ti, size_t start, size_t pad)
+{
+	char32_t *dbuf = malloc((INPUT_MAX_SIZE + 1) * sizeof(char32_t));
+	if (!dbuf)
+		return;
+
+	size_t sa;
+	size_t sb;
+	tinput_sel_get_bounds(ti, &sa, &sb);
+
+	tinput_console_set_lpos(ti, ti->text_coord + start);
+	console_set_style(ti->console, STYLE_NORMAL);
+
+	size_t p = start;
+	if (p < sa) {
+		memcpy(dbuf, ti->buffer + p, (sa - p) * sizeof(char32_t));
+		dbuf[sa - p] = '\0';
+		printf("%ls", dbuf);
+		p = sa;
+	}
+
+	if (p < sb) {
+		console_flush(ti->console);
+		console_set_style(ti->console, STYLE_SELECTED);
+
+		memcpy(dbuf, ti->buffer + p,
+		    (sb - p) * sizeof(char32_t));
+		dbuf[sb - p] = '\0';
+		printf("%ls", dbuf);
+		p = sb;
+	}
+
+	console_flush(ti->console);
+	console_set_style(ti->console, STYLE_NORMAL);
+
+	if (p < ti->nc) {
+		memcpy(dbuf, ti->buffer + p,
+		    (ti->nc - p) * sizeof(char32_t));
+		dbuf[ti->nc - p] = '\0';
+		printf("%ls", dbuf);
+	}
+
+	for (p = 0; p < pad; p++)
+		putuchar(' ');
+
+	console_flush(ti->console);
+
+	free(dbuf);
+}
+
+static char *tinput_get_str(tinput_t *ti)
+{
+	return wstr_to_astr(ti->buffer);
+}
+
+static void tinput_position_caret(tinput_t *ti)
+{
+	tinput_update_origin(ti);
+	tinput_console_set_lpos(ti, ti->text_coord + ti->pos);
+}
+
+/** Update text_coord, prompt_coord in case the screen would scroll
+ * due to @a end_coord being beyond the end of the screen
+ *
+ * @param ti Text input
+ * @param end_coord Linear screen coordinate to which the cursor would
+ *                  be moved if the screen would not have scrolled
+ */
+static void tinput_update_origin_coord(tinput_t *ti, unsigned end_coord)
+{
+	unsigned end_row = LIN_TO_ROW(ti, end_coord);
+
+	unsigned scroll_rows;
+
+	/* Update coords if the screen scrolled. */
+	if (end_row >= ti->con_rows) {
+		scroll_rows = end_row - ti->con_rows + 1;
+		ti->text_coord -= ti->con_cols * scroll_rows;
+		ti->prompt_coord -= ti->con_cols * scroll_rows;
+	}
+}
+
+/** Update text_coord, prompt_coord in case the screen could have scrolled. */
+static void tinput_update_origin(tinput_t *ti)
+{
+	/* Account for scrolling until the end of the input text */
+	tinput_update_origin_coord(ti, ti->text_coord + ti->nc);
+}
+
+static void tinput_jump_after(tinput_t *ti)
+{
+	tinput_console_set_lpos(ti, ti->text_coord + ti->nc);
+	console_flush(ti->console);
+	putuchar('\n');
+}
+
+static errno_t tinput_display(tinput_t *ti)
+{
+	sysarg_t col0, row0;
+
+	if (console_get_pos(ti->console, &col0, &row0) != EOK)
+		return EIO;
+
+	ti->prompt_coord = row0 * ti->con_cols + col0;
+	ti->text_coord = ti->prompt_coord;
+	tinput_display_prompt(ti);
+
+	/* The screen might have scrolled after priting the prompt */
+	tinput_update_origin_coord(ti, ti->prompt_coord + str_width(ti->prompt));
+
+	ti->text_coord = ti->prompt_coord + str_length(ti->prompt);
+	tinput_display_tail(ti, 0, 0);
+
+	/* The screen might have scrolled after priting the text */
+	tinput_update_origin(ti);
+
+	tinput_position_caret(ti);
+
+	return EOK;
+}
+
+static void tinput_insert_char(tinput_t *ti, char32_t c)
+{
+	if (ti->nc == INPUT_MAX_SIZE)
+		return;
+
+	unsigned new_width = LIN_TO_COL(ti, ti->text_coord) + ti->nc + 1;
+	if (new_width % ti->con_cols == 0) {
+		/* Advancing to new line. */
+		sysarg_t new_height = (new_width / ti->con_cols) + 1;
+		if (new_height >= ti->con_rows) {
+			/* Disallow text longer than 1 page for now. */
+			return;
+		}
+	}
+
+	size_t i;
+	for (i = ti->nc; i > ti->pos; i--)
+		ti->buffer[i] = ti->buffer[i - 1];
+
+	ti->buffer[ti->pos] = c;
+	ti->pos += 1;
+	ti->nc += 1;
+	ti->buffer[ti->nc] = '\0';
+	ti->sel_start = ti->pos;
+
+	tinput_display_tail(ti, ti->pos - 1, 0);
+	tinput_position_caret(ti);
+}
+
+static void tinput_insert_string(tinput_t *ti, const char *str)
+{
+	size_t ilen = min(str_length(str), INPUT_MAX_SIZE - ti->nc);
+	if (ilen == 0)
+		return;
+
+	unsigned new_width = LIN_TO_COL(ti, ti->text_coord) + ti->nc + ilen;
+	unsigned new_height = (new_width / ti->con_cols) + 1;
+	if (new_height >= ti->con_rows) {
+		/* Disallow text longer than 1 page for now. */
+		return;
+	}
+
+	if (ti->nc > 0) {
+		size_t i;
+		for (i = ti->nc; i > ti->pos; i--)
+			ti->buffer[i + ilen - 1] = ti->buffer[i - 1];
+	}
+
+	size_t off = 0;
+	size_t i = 0;
+	while (i < ilen) {
+		char32_t c = str_decode(str, &off, STR_NO_LIMIT);
+		if (c == '\0')
+			break;
+
+		/* Filter out non-printable chars. */
+		if (c < 32)
+			c = 32;
+
+		ti->buffer[ti->pos + i] = c;
+		i++;
+	}
+
+	ti->pos += ilen;
+	ti->nc += ilen;
+	ti->buffer[ti->nc] = '\0';
+	ti->sel_start = ti->pos;
+
+	tinput_display_tail(ti, ti->pos - ilen, 0);
+	tinput_position_caret(ti);
+}
+
+static void tinput_backspace(tinput_t *ti)
+{
+	if (tinput_sel_active(ti)) {
+		tinput_sel_delete(ti);
+		return;
+	}
+
+	if (ti->pos == 0)
+		return;
+
+	size_t i;
+	for (i = ti->pos; i < ti->nc; i++)
+		ti->buffer[i - 1] = ti->buffer[i];
+
+	ti->pos -= 1;
+	ti->nc -= 1;
+	ti->buffer[ti->nc] = '\0';
+	ti->sel_start = ti->pos;
+
+	tinput_display_tail(ti, ti->pos, 1);
+	tinput_position_caret(ti);
+}
+
+static void tinput_delete(tinput_t *ti)
+{
+	if (tinput_sel_active(ti)) {
+		tinput_sel_delete(ti);
+		return;
+	}
+
+	if (ti->pos == ti->nc)
+		return;
+
+	ti->pos += 1;
+	ti->sel_start = ti->pos;
+
+	tinput_backspace(ti);
+}
+
+static void tinput_seek_cell(tinput_t *ti, seek_dir_t dir, bool shift_held)
+{
+	tinput_pre_seek(ti, shift_held);
+
+	if (dir == seek_forward) {
+		if (ti->pos < ti->nc)
+			ti->pos += 1;
+	} else {
+		if (ti->pos > 0)
+			ti->pos -= 1;
+	}
+
+	tinput_post_seek(ti, shift_held);
+}
+
+static void tinput_seek_word(tinput_t *ti, seek_dir_t dir, bool shift_held)
+{
+	tinput_pre_seek(ti, shift_held);
+
+	if (dir == seek_forward) {
+		if (ti->pos == ti->nc)
+			return;
+
+		while (true) {
+			ti->pos += 1;
+
+			if (ti->pos == ti->nc)
+				break;
+
+			if ((ti->buffer[ti->pos - 1] == ' ') &&
+			    (ti->buffer[ti->pos] != ' '))
+				break;
+		}
+	} else {
+		if (ti->pos == 0)
+			return;
+
+		while (true) {
+			ti->pos -= 1;
+
+			if (ti->pos == 0)
+				break;
+
+			if (ti->buffer[ti->pos - 1] == ' ' &&
+			    ti->buffer[ti->pos] != ' ')
+				break;
+		}
+
+	}
+
+	tinput_post_seek(ti, shift_held);
+}
+
+static void tinput_seek_vertical(tinput_t *ti, seek_dir_t dir, bool shift_held)
+{
+	tinput_pre_seek(ti, shift_held);
+
+	if (dir == seek_forward) {
+		if (ti->pos + ti->con_cols <= ti->nc)
+			ti->pos = ti->pos + ti->con_cols;
+	} else {
+		if (ti->pos >= ti->con_cols)
+			ti->pos = ti->pos - ti->con_cols;
+	}
+
+	tinput_post_seek(ti, shift_held);
+}
+
+static void tinput_seek_scrpos(tinput_t *ti, int col, int line, bool shift_held)
+{
+	unsigned lpos;
+	tinput_pre_seek(ti, shift_held);
+
+	lpos = LIN_POS(ti, col, line);
+
+	if (lpos > ti->text_coord)
+		ti->pos = lpos -  ti->text_coord;
+	else
+		ti->pos = 0;
+	if (ti->pos > ti->nc)
+		ti->pos = ti->nc;
+
+	tinput_post_seek(ti, shift_held);
+}
+
+static void tinput_seek_max(tinput_t *ti, seek_dir_t dir, bool shift_held)
+{
+	tinput_pre_seek(ti, shift_held);
+
+	if (dir == seek_backward)
+		ti->pos = 0;
+	else
+		ti->pos = ti->nc;
+
+	tinput_post_seek(ti, shift_held);
+}
+
+static void tinput_pre_seek(tinput_t *ti, bool shift_held)
+{
+	if ((tinput_sel_active(ti)) && (!shift_held)) {
+		/* Unselect and redraw. */
+		ti->sel_start = ti->pos;
+		tinput_display_tail(ti, 0, 0);
+		tinput_position_caret(ti);
+	}
+}
+
+static void tinput_post_seek(tinput_t *ti, bool shift_held)
+{
+	if (shift_held) {
+		/* Selecting text. Need redraw. */
+		tinput_display_tail(ti, 0, 0);
+	} else {
+		/* Shift not held. Keep selection empty. */
+		ti->sel_start = ti->pos;
+	}
+
+	tinput_position_caret(ti);
+}
+
+static void tinput_history_insert(tinput_t *ti, char *str)
+{
+	if (ti->hnum < HISTORY_LEN) {
+		ti->hnum += 1;
+	} else {
+		if (ti->history[HISTORY_LEN] != NULL)
+			free(ti->history[HISTORY_LEN]);
+	}
+
+	size_t i;
+	for (i = ti->hnum; i > 1; i--)
+		ti->history[i] = ti->history[i - 1];
+
+	ti->history[1] = str_dup(str);
+
+	if (ti->history[0] != NULL) {
+		free(ti->history[0]);
+		ti->history[0] = NULL;
+	}
+}
+
+static void tinput_set_str(tinput_t *ti, const char *str)
+{
+	str_to_wstr(ti->buffer, INPUT_MAX_SIZE, str);
+	ti->nc = wstr_length(ti->buffer);
+	ti->pos = ti->nc;
+	ti->sel_start = ti->pos;
+}
+
+static void tinput_sel_get_bounds(tinput_t *ti, size_t *sa, size_t *sb)
+{
+	if (ti->sel_start < ti->pos) {
+		*sa = ti->sel_start;
+		*sb = ti->pos;
+	} else {
+		*sa = ti->pos;
+		*sb = ti->sel_start;
+	}
+}
+
+static bool tinput_sel_active(tinput_t *ti)
+{
+	return (ti->sel_start != ti->pos);
+}
+
+static void tinput_sel_all(tinput_t *ti)
+{
+	ti->sel_start = 0;
+	ti->pos = ti->nc;
+	tinput_display_tail(ti, 0, 0);
+	tinput_position_caret(ti);
+}
+
+static void tinput_sel_delete(tinput_t *ti)
+{
+	size_t sa;
+	size_t sb;
+
+	tinput_sel_get_bounds(ti, &sa, &sb);
+	if (sa == sb)
+		return;
+
+	memmove(ti->buffer + sa, ti->buffer + sb,
+	    (ti->nc - sb) * sizeof(char32_t));
+
+	ti->pos = ti->sel_start = sa;
+	ti->nc -= (sb - sa);
+	ti->buffer[ti->nc] = '\0';
+
+	tinput_display_tail(ti, sa, sb - sa);
+	tinput_position_caret(ti);
+}
+
+static void tinput_sel_copy_to_cb(tinput_t *ti)
+{
+	size_t sa;
+	size_t sb;
+
+	tinput_sel_get_bounds(ti, &sa, &sb);
+
+	char *str;
+
+	if (sb < ti->nc) {
+		char32_t tmp_c = ti->buffer[sb];
+		ti->buffer[sb] = '\0';
+		str = wstr_to_astr(ti->buffer + sa);
+		ti->buffer[sb] = tmp_c;
+	} else
+		str = wstr_to_astr(ti->buffer + sa);
+
+	if (str == NULL)
+		goto error;
+
+	if (clipboard_put_str(str) != EOK)
+		goto error;
+
+	free(str);
+	return;
+
+error:
+	/* TODO: Give the user some kind of warning. */
+	return;
+}
+
+static void tinput_paste_from_cb(tinput_t *ti)
+{
+	char *str;
+	errno_t rc = clipboard_get_str(&str);
+
+	if ((rc != EOK) || (str == NULL)) {
+		/* TODO: Give the user some kind of warning. */
+		return;
+	}
+
+	tinput_insert_string(ti, str);
+	free(str);
+}
+
+static void tinput_history_seek(tinput_t *ti, int offs)
+{
+	if (offs >= 0) {
+		if (ti->hpos + offs > ti->hnum)
+			return;
+	} else {
+		if (ti->hpos < (size_t) -offs)
+			return;
+	}
+
+	if (ti->history[ti->hpos] != NULL) {
+		free(ti->history[ti->hpos]);
+		ti->history[ti->hpos] = NULL;
+	}
+
+	ti->history[ti->hpos] = tinput_get_str(ti);
+	ti->hpos += offs;
+
+	int pad = (int) ti->nc - str_length(ti->history[ti->hpos]);
+	if (pad < 0)
+		pad = 0;
+
+	tinput_set_str(ti, ti->history[ti->hpos]);
+	tinput_display_tail(ti, 0, pad);
+	tinput_update_origin(ti);
+	tinput_position_caret(ti);
+}
+
+/** Compare two entries in array of completions. */
+static int compl_cmp(const void *va, const void *vb)
+{
+	const char *a = *(const char **) va;
+	const char *b = *(const char **) vb;
+
+	return str_cmp(a, b);
+}
+
+static size_t common_pref_len(const char *a, const char *b)
+{
+	size_t i;
+	size_t a_off, b_off;
+	char32_t ca, cb;
+
+	i = 0;
+	a_off = 0;
+	b_off = 0;
+
+	while (true) {
+		ca = str_decode(a, &a_off, STR_NO_LIMIT);
+		cb = str_decode(b, &b_off, STR_NO_LIMIT);
+
+		if (ca == '\0' || cb == '\0' || ca != cb)
+			break;
+		++i;
+	}
+
+	return i;
+}
+
+/* Print a list of completions */
+static void tinput_show_completions(tinput_t *ti, char **compl, size_t cnum)
+{
+	unsigned int i;
+	/* Determine the maximum width of the completion in chars */
+	size_t max_width = 0;
+	for (i = 0; i < cnum; i++)
+		max_width = max(max_width, str_width(compl[i]));
+
+	unsigned int cols = max(1, (ti->con_cols + 1) / (max_width + 1));
+	unsigned int padding = 0;
+	if (cols * max_width + (cols - 1) < ti->con_cols) {
+		padding = ti->con_cols - cols * max_width - (cols - 1);
+	}
+	unsigned int col_width = max_width + padding / cols;
+	unsigned int rows = cnum / cols + ((cnum % cols) != 0);
+
+	unsigned int row, col;
+
+	for (row = 0; row < rows; row++) {
+		unsigned int display_col = 0;
+		for (col = 0; col < cols; col++) {
+			size_t compl_idx = col * rows + row;
+			if (compl_idx >= cnum)
+				break;
+			if (col) {
+				printf(" ");
+				display_col++;
+			}
+			printf("%s", compl[compl_idx]);
+			size_t compl_width = str_width(compl[compl_idx]);
+			display_col += compl_width;
+			if (col < cols - 1) {
+				for (i = compl_width; i < col_width; i++) {
+					printf(" ");
+					display_col++;
+				}
+			}
+		}
+		if ((display_col % ti->con_cols) > 0)
+			printf("\n");
+	}
+	fflush(stdout);
+}
+
+static void tinput_text_complete(tinput_t *ti)
+{
+	void *state;
+	size_t cstart;
+	char *ctmp;
+	char **compl;     	/* Array of completions */
+	size_t compl_len;	/* Current length of @c compl array */
+	size_t cnum;
+	size_t i;
+	errno_t rc;
+
+	if (ti->compl_ops == NULL)
+		return;
+
+	/*
+	 * Obtain list of all possible completions (growing array).
+	 */
+
+	rc = (*ti->compl_ops->init)(ti->buffer, ti->pos, &cstart, &state);
+	if (rc != EOK)
+		return;
+
+	cnum = 0;
+
+	compl_len = 1;
+	compl = malloc(compl_len * sizeof(char *));
+	if (compl == NULL) {
+		printf("Error: Out of memory.\n");
+		return;
+	}
+
+	while (true) {
+		rc = (*ti->compl_ops->get_next)(state, &ctmp);
+		if (rc != EOK)
+			break;
+
+		if (cnum >= compl_len) {
+			/* Extend array */
+			compl_len = 2 * compl_len;
+			char **temp = realloc(compl, compl_len * sizeof(char *));
+			if (temp == NULL) {
+				free(compl);
+				printf("Error: Out of memory.\n");
+				break;
+			}
+			compl = temp;
+		}
+
+		compl[cnum] = str_dup(ctmp);
+		if (compl[cnum] == NULL) {
+			printf("Error: Out of memory.\n");
+			break;
+		}
+		cnum++;
+	}
+
+	(*ti->compl_ops->fini)(state);
+
+	if (cnum > 1) {
+		/*
+		 * More than one match. Determine maximum common prefix.
+		 */
+		size_t cplen;
+
+		cplen = str_length(compl[0]);
+		for (i = 1; i < cnum; i++)
+			cplen = min(cplen, common_pref_len(compl[0], compl[i]));
+
+		/* Compute how many bytes we should skip. */
+		size_t istart = str_lsize(compl[0], ti->pos - cstart);
+
+		if (cplen > istart) {
+			/* Insert common prefix. */
+
+			/* Copy remainder of common prefix. */
+			char *cpref = str_ndup(compl[0] + istart,
+			    str_lsize(compl[0], cplen - istart));
+
+			/* Insert it. */
+			tinput_insert_string(ti, cpref);
+			free(cpref);
+		} else {
+			/* No common prefix. Sort and display all entries. */
+
+			qsort(compl, cnum, sizeof(char *), compl_cmp);
+
+			tinput_jump_after(ti);
+			tinput_show_completions(ti, compl, cnum);
+			tinput_display(ti);
+		}
+	} else if (cnum == 1) {
+		/*
+		 * We have exactly one match. Insert it.
+		 */
+
+		/* Compute how many bytes of completion string we should skip. */
+		size_t istart = str_lsize(compl[0], ti->pos - cstart);
+
+		/* Insert remainder of completion string at current position. */
+		tinput_insert_string(ti, compl[0] + istart);
+	}
+
+	for (i = 0; i < cnum; i++)
+		free(compl[i]);
+	free(compl);
+}
+
+/** Initialize text input field.
+ *
+ * Must be called before using the field. It clears the history.
+ */
+static void tinput_init(tinput_t *ti)
+{
+	ti->console = console_init(stdin, stdout);
+	ti->hnum = 0;
+	ti->hpos = 0;
+	ti->history[0] = NULL;
+}
+
+/** Set prompt string.
+ *
+ * @param ti		Text input
+ * @param prompt	Prompt string
+ *
+ * @return		EOK on success, ENOMEM if out of memory.
+ */
+errno_t tinput_set_prompt(tinput_t *ti, const char *prompt)
+{
+	if (ti->prompt != NULL)
+		free(ti->prompt);
+
+	ti->prompt = str_dup(prompt);
+	if (ti->prompt == NULL)
+		return ENOMEM;
+
+	return EOK;
+}
+
+/** Set completion ops.
+ *
+ * Set pointer to completion ops structure that will be used for text
+ * completion.
+ */
+void tinput_set_compl_ops(tinput_t *ti, tinput_compl_ops_t *compl_ops)
+{
+	ti->compl_ops = compl_ops;
+}
+
+/** Handle key press event. */
+static void tinput_key_press(tinput_t *ti, kbd_event_t *kev)
+{
+	if (kev->key == KC_LSHIFT)
+		ti->lshift_held = true;
+	if (kev->key == KC_RSHIFT)
+		ti->rshift_held = true;
+
+	if (((kev->mods & KM_CTRL) != 0) &&
+	    ((kev->mods & (KM_ALT | KM_SHIFT)) == 0))
+		tinput_key_ctrl(ti, kev);
+
+	if (((kev->mods & KM_SHIFT) != 0) &&
+	    ((kev->mods & (KM_CTRL | KM_ALT)) == 0))
+		tinput_key_shift(ti, kev);
+
+	if (((kev->mods & KM_CTRL) != 0) &&
+	    ((kev->mods & KM_SHIFT) != 0) &&
+	    ((kev->mods & KM_ALT) == 0))
+		tinput_key_ctrl_shift(ti, kev);
+
+	if ((kev->mods & (KM_CTRL | KM_ALT | KM_SHIFT)) == 0)
+		tinput_key_unmod(ti, kev);
+
+	if (((kev->mods & (KM_CTRL | KM_ALT)) == 0) && kev->c >= ' ') {
+		tinput_sel_delete(ti);
+		tinput_insert_char(ti, kev->c);
+	}
+}
+
+/** Handle key release event. */
+static void tinput_key_release(tinput_t *ti, kbd_event_t *kev)
+{
+	if (kev->key == KC_LSHIFT)
+		ti->lshift_held = false;
+	if (kev->key == KC_RSHIFT)
+		ti->rshift_held = false;
+}
+
+/** Position event */
+static void tinput_pos(tinput_t *ti, pos_event_t *ev)
+{
+	if (ev->type == POS_PRESS) {
+		tinput_seek_scrpos(ti, ev->hpos, ev->vpos,
+		    ti->lshift_held || ti->rshift_held);
+	}
+}
+
+/** Read in one line of input with initial text provided.
+ *
+ * @param ti   Text input
+ * @param istr Initial string
+ * @param dstr Place to save pointer to new string
+ *
+ * @return EOK on success
+ * @return ENOENT if user requested abort
+ * @return EIO if communication with console failed
+ *
+ */
+errno_t tinput_read_i(tinput_t *ti, const char *istr, char **dstr)
+{
+	errno_t rc;
+
+	console_flush(ti->console);
+	if (console_get_size(ti->console, &ti->con_cols, &ti->con_rows) != EOK)
+		return EIO;
+
+	tinput_set_str(ti, istr);
+
+	ti->sel_start = 0;
+	ti->done = false;
+	ti->exit_clui = false;
+
+	if (tinput_display(ti) != EOK)
+		return EIO;
+
+	while (!ti->done) {
+		console_flush(ti->console);
+
+		cons_event_t ev;
+		rc = console_get_event(ti->console, &ev);
+		if (rc != EOK)
+			return EIO;
+
+		switch (ev.type) {
+		case CEV_KEY:
+			if (ev.ev.key.type == KEY_PRESS)
+				tinput_key_press(ti, &ev.ev.key);
+			else
+				tinput_key_release(ti, &ev.ev.key);
+			break;
+		case CEV_POS:
+			tinput_pos(ti, &ev.ev.pos);
+			break;
+		}
+	}
+
+	if (ti->exit_clui)
+		return ENOENT;
+
+	ti->pos = ti->nc;
+	tinput_position_caret(ti);
+	putchar('\n');
+
+	char *str = tinput_get_str(ti);
+	if (str_cmp(str, "") != 0)
+		tinput_history_insert(ti, str);
+
+	ti->hpos = 0;
+
+	*dstr = str;
+	return EOK;
+}
+
+/** Read in one line of input.
+ *
+ * @param ti   Text input
+ * @param dstr Place to save pointer to new string.
+ *
+ * @return EOK on success
+ * @return ENOENT if user requested abort
+ * @return EIO if communication with console failed
+ *
+ */
+errno_t tinput_read(tinput_t *ti, char **dstr)
+{
+	return tinput_read_i(ti, "", dstr);
+}
+
+static void tinput_key_ctrl(tinput_t *ti, kbd_event_t *ev)
+{
+	switch (ev->key) {
+	case KC_LEFT:
+		tinput_seek_word(ti, seek_backward, false);
+		break;
+	case KC_RIGHT:
+		tinput_seek_word(ti, seek_forward, false);
+		break;
+	case KC_UP:
+		tinput_seek_vertical(ti, seek_backward, false);
+		break;
+	case KC_DOWN:
+		tinput_seek_vertical(ti, seek_forward, false);
+		break;
+	case KC_X:
+		tinput_sel_copy_to_cb(ti);
+		tinput_sel_delete(ti);
+		break;
+	case KC_C:
+		tinput_sel_copy_to_cb(ti);
+		break;
+	case KC_V:
+		tinput_sel_delete(ti);
+		tinput_paste_from_cb(ti);
+		break;
+	case KC_A:
+		tinput_sel_all(ti);
+		break;
+	case KC_Q:
+		/* Signal libary client to quit interactive loop. */
+		ti->done = true;
+		ti->exit_clui = true;
+		break;
+	default:
+		break;
+	}
+}
+
+static void tinput_key_ctrl_shift(tinput_t *ti, kbd_event_t *ev)
+{
+	switch (ev->key) {
+	case KC_LEFT:
+		tinput_seek_word(ti, seek_backward, true);
+		break;
+	case KC_RIGHT:
+		tinput_seek_word(ti, seek_forward, true);
+		break;
+	case KC_UP:
+		tinput_seek_vertical(ti, seek_backward, true);
+		break;
+	case KC_DOWN:
+		tinput_seek_vertical(ti, seek_forward, true);
+		break;
+	default:
+		break;
+	}
+}
+
+static void tinput_key_shift(tinput_t *ti, kbd_event_t *ev)
+{
+	switch (ev->key) {
+	case KC_LEFT:
+		tinput_seek_cell(ti, seek_backward, true);
+		break;
+	case KC_RIGHT:
+		tinput_seek_cell(ti, seek_forward, true);
+		break;
+	case KC_UP:
+		tinput_seek_vertical(ti, seek_backward, true);
+		break;
+	case KC_DOWN:
+		tinput_seek_vertical(ti, seek_forward, true);
+		break;
+	case KC_HOME:
+		tinput_seek_max(ti, seek_backward, true);
+		break;
+	case KC_END:
+		tinput_seek_max(ti, seek_forward, true);
+		break;
+	default:
+		break;
+	}
+}
+
+static void tinput_key_unmod(tinput_t *ti, kbd_event_t *ev)
+{
+	switch (ev->key) {
+	case KC_ENTER:
+	case KC_NENTER:
+		ti->done = true;
+		break;
+	case KC_BACKSPACE:
+		tinput_backspace(ti);
+		break;
+	case KC_DELETE:
+		tinput_delete(ti);
+		break;
+	case KC_LEFT:
+		tinput_seek_cell(ti, seek_backward, false);
+		break;
+	case KC_RIGHT:
+		tinput_seek_cell(ti, seek_forward, false);
+		break;
+	case KC_HOME:
+		tinput_seek_max(ti, seek_backward, false);
+		break;
+	case KC_END:
+		tinput_seek_max(ti, seek_forward, false);
+		break;
+	case KC_UP:
+		tinput_history_seek(ti, 1);
+		break;
+	case KC_DOWN:
+		tinput_history_seek(ti, -1);
+		break;
+	case KC_TAB:
+		tinput_text_complete(ti);
+		break;
+	default:
+		break;
+	}
+}
+
+/**
+ * @}
+ */
Index: uspace/lib/clui/tinput.c
===================================================================
--- uspace/lib/clui/tinput.c	(revision 00e62883ce36dafecb81ee65875c0b6a4529130b)
+++ 	(revision )
@@ -1,1090 +1,0 @@
-/*
- * Copyright (c) 2011 Jiri Svoboda
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistributions of source code must retain the above copyright
- *   notice, this list of conditions and the following disclaimer.
- * - Redistributions in binary form must reproduce the above copyright
- *   notice, this list of conditions and the following disclaimer in the
- *   documentation and/or other materials provided with the distribution.
- * - The name of the author may not be used to endorse or promote products
- *   derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-/** @addtogroup libclui
- * @{
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <str.h>
-#include <io/console.h>
-#include <io/keycode.h>
-#include <io/style.h>
-#include <io/color.h>
-#include <vfs/vfs.h>
-#include <clipboard.h>
-#include <macros.h>
-#include <errno.h>
-#include <assert.h>
-#include <stdbool.h>
-#include <tinput.h>
-
-#define LIN_TO_COL(ti, lpos) ((lpos) % ((ti)->con_cols))
-#define LIN_TO_ROW(ti, lpos) ((lpos) / ((ti)->con_cols))
-#define LIN_POS(ti, col, row) ((col) + (row) * (ti)->con_cols)
-
-/** Seek direction */
-typedef enum {
-	seek_backward = -1,
-	seek_forward = 1
-} seek_dir_t;
-
-static void tinput_update_origin(tinput_t *);
-static void tinput_init(tinput_t *);
-static void tinput_insert_string(tinput_t *, const char *);
-static void tinput_sel_get_bounds(tinput_t *, size_t *, size_t *);
-static bool tinput_sel_active(tinput_t *);
-static void tinput_sel_all(tinput_t *);
-static void tinput_sel_delete(tinput_t *);
-static void tinput_key_ctrl(tinput_t *, kbd_event_t *);
-static void tinput_key_shift(tinput_t *, kbd_event_t *);
-static void tinput_key_ctrl_shift(tinput_t *, kbd_event_t *);
-static void tinput_key_unmod(tinput_t *, kbd_event_t *);
-static void tinput_pre_seek(tinput_t *, bool);
-static void tinput_post_seek(tinput_t *, bool);
-
-static void tinput_console_set_lpos(tinput_t *ti, unsigned lpos)
-{
-	unsigned col = LIN_TO_COL(ti, lpos);
-	unsigned row = LIN_TO_ROW(ti, lpos);
-
-	assert(col < ti->con_cols);
-	assert(row < ti->con_rows);
-	console_set_pos(ti->console, col, row);
-}
-
-/** Create a new text input field. */
-tinput_t *tinput_new(void)
-{
-	tinput_t *ti;
-
-	ti = calloc(1, sizeof(tinput_t));
-	if (ti == NULL)
-		return NULL;
-
-	tinput_init(ti);
-	return ti;
-}
-
-/** Destroy text input field. */
-void tinput_destroy(tinput_t *ti)
-{
-	if (ti->prompt != NULL)
-		free(ti->prompt);
-	free(ti);
-}
-
-static void tinput_display_prompt(tinput_t *ti)
-{
-	tinput_console_set_lpos(ti, ti->prompt_coord);
-
-	console_set_style(ti->console, STYLE_EMPHASIS);
-	printf("%s", ti->prompt);
-	console_flush(ti->console);
-	console_set_style(ti->console, STYLE_NORMAL);
-}
-
-static void tinput_display_tail(tinput_t *ti, size_t start, size_t pad)
-{
-	char32_t *dbuf = malloc((INPUT_MAX_SIZE + 1) * sizeof(char32_t));
-	if (!dbuf)
-		return;
-
-	size_t sa;
-	size_t sb;
-	tinput_sel_get_bounds(ti, &sa, &sb);
-
-	tinput_console_set_lpos(ti, ti->text_coord + start);
-	console_set_style(ti->console, STYLE_NORMAL);
-
-	size_t p = start;
-	if (p < sa) {
-		memcpy(dbuf, ti->buffer + p, (sa - p) * sizeof(char32_t));
-		dbuf[sa - p] = '\0';
-		printf("%ls", dbuf);
-		p = sa;
-	}
-
-	if (p < sb) {
-		console_flush(ti->console);
-		console_set_style(ti->console, STYLE_SELECTED);
-
-		memcpy(dbuf, ti->buffer + p,
-		    (sb - p) * sizeof(char32_t));
-		dbuf[sb - p] = '\0';
-		printf("%ls", dbuf);
-		p = sb;
-	}
-
-	console_flush(ti->console);
-	console_set_style(ti->console, STYLE_NORMAL);
-
-	if (p < ti->nc) {
-		memcpy(dbuf, ti->buffer + p,
-		    (ti->nc - p) * sizeof(char32_t));
-		dbuf[ti->nc - p] = '\0';
-		printf("%ls", dbuf);
-	}
-
-	for (p = 0; p < pad; p++)
-		putuchar(' ');
-
-	console_flush(ti->console);
-
-	free(dbuf);
-}
-
-static char *tinput_get_str(tinput_t *ti)
-{
-	return wstr_to_astr(ti->buffer);
-}
-
-static void tinput_position_caret(tinput_t *ti)
-{
-	tinput_update_origin(ti);
-	tinput_console_set_lpos(ti, ti->text_coord + ti->pos);
-}
-
-/** Update text_coord, prompt_coord in case the screen would scroll
- * due to @a end_coord being beyond the end of the screen
- *
- * @param ti Text input
- * @param end_coord Linear screen coordinate to which the cursor would
- *                  be moved if the screen would not have scrolled
- */
-static void tinput_update_origin_coord(tinput_t *ti, unsigned end_coord)
-{
-	unsigned end_row = LIN_TO_ROW(ti, end_coord);
-
-	unsigned scroll_rows;
-
-	/* Update coords if the screen scrolled. */
-	if (end_row >= ti->con_rows) {
-		scroll_rows = end_row - ti->con_rows + 1;
-		ti->text_coord -= ti->con_cols * scroll_rows;
-		ti->prompt_coord -= ti->con_cols * scroll_rows;
-	}
-}
-
-/** Update text_coord, prompt_coord in case the screen could have scrolled. */
-static void tinput_update_origin(tinput_t *ti)
-{
-	/* Account for scrolling until the end of the input text */
-	tinput_update_origin_coord(ti, ti->text_coord + ti->nc);
-}
-
-static void tinput_jump_after(tinput_t *ti)
-{
-	tinput_console_set_lpos(ti, ti->text_coord + ti->nc);
-	console_flush(ti->console);
-	putuchar('\n');
-}
-
-static errno_t tinput_display(tinput_t *ti)
-{
-	sysarg_t col0, row0;
-
-	if (console_get_pos(ti->console, &col0, &row0) != EOK)
-		return EIO;
-
-	ti->prompt_coord = row0 * ti->con_cols + col0;
-	ti->text_coord = ti->prompt_coord;
-	tinput_display_prompt(ti);
-
-	/* The screen might have scrolled after priting the prompt */
-	tinput_update_origin_coord(ti, ti->prompt_coord + str_width(ti->prompt));
-
-	ti->text_coord = ti->prompt_coord + str_length(ti->prompt);
-	tinput_display_tail(ti, 0, 0);
-
-	/* The screen might have scrolled after priting the text */
-	tinput_update_origin(ti);
-
-	tinput_position_caret(ti);
-
-	return EOK;
-}
-
-static void tinput_insert_char(tinput_t *ti, char32_t c)
-{
-	if (ti->nc == INPUT_MAX_SIZE)
-		return;
-
-	unsigned new_width = LIN_TO_COL(ti, ti->text_coord) + ti->nc + 1;
-	if (new_width % ti->con_cols == 0) {
-		/* Advancing to new line. */
-		sysarg_t new_height = (new_width / ti->con_cols) + 1;
-		if (new_height >= ti->con_rows) {
-			/* Disallow text longer than 1 page for now. */
-			return;
-		}
-	}
-
-	size_t i;
-	for (i = ti->nc; i > ti->pos; i--)
-		ti->buffer[i] = ti->buffer[i - 1];
-
-	ti->buffer[ti->pos] = c;
-	ti->pos += 1;
-	ti->nc += 1;
-	ti->buffer[ti->nc] = '\0';
-	ti->sel_start = ti->pos;
-
-	tinput_display_tail(ti, ti->pos - 1, 0);
-	tinput_position_caret(ti);
-}
-
-static void tinput_insert_string(tinput_t *ti, const char *str)
-{
-	size_t ilen = min(str_length(str), INPUT_MAX_SIZE - ti->nc);
-	if (ilen == 0)
-		return;
-
-	unsigned new_width = LIN_TO_COL(ti, ti->text_coord) + ti->nc + ilen;
-	unsigned new_height = (new_width / ti->con_cols) + 1;
-	if (new_height >= ti->con_rows) {
-		/* Disallow text longer than 1 page for now. */
-		return;
-	}
-
-	if (ti->nc > 0) {
-		size_t i;
-		for (i = ti->nc; i > ti->pos; i--)
-			ti->buffer[i + ilen - 1] = ti->buffer[i - 1];
-	}
-
-	size_t off = 0;
-	size_t i = 0;
-	while (i < ilen) {
-		char32_t c = str_decode(str, &off, STR_NO_LIMIT);
-		if (c == '\0')
-			break;
-
-		/* Filter out non-printable chars. */
-		if (c < 32)
-			c = 32;
-
-		ti->buffer[ti->pos + i] = c;
-		i++;
-	}
-
-	ti->pos += ilen;
-	ti->nc += ilen;
-	ti->buffer[ti->nc] = '\0';
-	ti->sel_start = ti->pos;
-
-	tinput_display_tail(ti, ti->pos - ilen, 0);
-	tinput_position_caret(ti);
-}
-
-static void tinput_backspace(tinput_t *ti)
-{
-	if (tinput_sel_active(ti)) {
-		tinput_sel_delete(ti);
-		return;
-	}
-
-	if (ti->pos == 0)
-		return;
-
-	size_t i;
-	for (i = ti->pos; i < ti->nc; i++)
-		ti->buffer[i - 1] = ti->buffer[i];
-
-	ti->pos -= 1;
-	ti->nc -= 1;
-	ti->buffer[ti->nc] = '\0';
-	ti->sel_start = ti->pos;
-
-	tinput_display_tail(ti, ti->pos, 1);
-	tinput_position_caret(ti);
-}
-
-static void tinput_delete(tinput_t *ti)
-{
-	if (tinput_sel_active(ti)) {
-		tinput_sel_delete(ti);
-		return;
-	}
-
-	if (ti->pos == ti->nc)
-		return;
-
-	ti->pos += 1;
-	ti->sel_start = ti->pos;
-
-	tinput_backspace(ti);
-}
-
-static void tinput_seek_cell(tinput_t *ti, seek_dir_t dir, bool shift_held)
-{
-	tinput_pre_seek(ti, shift_held);
-
-	if (dir == seek_forward) {
-		if (ti->pos < ti->nc)
-			ti->pos += 1;
-	} else {
-		if (ti->pos > 0)
-			ti->pos -= 1;
-	}
-
-	tinput_post_seek(ti, shift_held);
-}
-
-static void tinput_seek_word(tinput_t *ti, seek_dir_t dir, bool shift_held)
-{
-	tinput_pre_seek(ti, shift_held);
-
-	if (dir == seek_forward) {
-		if (ti->pos == ti->nc)
-			return;
-
-		while (true) {
-			ti->pos += 1;
-
-			if (ti->pos == ti->nc)
-				break;
-
-			if ((ti->buffer[ti->pos - 1] == ' ') &&
-			    (ti->buffer[ti->pos] != ' '))
-				break;
-		}
-	} else {
-		if (ti->pos == 0)
-			return;
-
-		while (true) {
-			ti->pos -= 1;
-
-			if (ti->pos == 0)
-				break;
-
-			if (ti->buffer[ti->pos - 1] == ' ' &&
-			    ti->buffer[ti->pos] != ' ')
-				break;
-		}
-
-	}
-
-	tinput_post_seek(ti, shift_held);
-}
-
-static void tinput_seek_vertical(tinput_t *ti, seek_dir_t dir, bool shift_held)
-{
-	tinput_pre_seek(ti, shift_held);
-
-	if (dir == seek_forward) {
-		if (ti->pos + ti->con_cols <= ti->nc)
-			ti->pos = ti->pos + ti->con_cols;
-	} else {
-		if (ti->pos >= ti->con_cols)
-			ti->pos = ti->pos - ti->con_cols;
-	}
-
-	tinput_post_seek(ti, shift_held);
-}
-
-static void tinput_seek_scrpos(tinput_t *ti, int col, int line, bool shift_held)
-{
-	unsigned lpos;
-	tinput_pre_seek(ti, shift_held);
-
-	lpos = LIN_POS(ti, col, line);
-
-	if (lpos > ti->text_coord)
-		ti->pos = lpos -  ti->text_coord;
-	else
-		ti->pos = 0;
-	if (ti->pos > ti->nc)
-		ti->pos = ti->nc;
-
-	tinput_post_seek(ti, shift_held);
-}
-
-static void tinput_seek_max(tinput_t *ti, seek_dir_t dir, bool shift_held)
-{
-	tinput_pre_seek(ti, shift_held);
-
-	if (dir == seek_backward)
-		ti->pos = 0;
-	else
-		ti->pos = ti->nc;
-
-	tinput_post_seek(ti, shift_held);
-}
-
-static void tinput_pre_seek(tinput_t *ti, bool shift_held)
-{
-	if ((tinput_sel_active(ti)) && (!shift_held)) {
-		/* Unselect and redraw. */
-		ti->sel_start = ti->pos;
-		tinput_display_tail(ti, 0, 0);
-		tinput_position_caret(ti);
-	}
-}
-
-static void tinput_post_seek(tinput_t *ti, bool shift_held)
-{
-	if (shift_held) {
-		/* Selecting text. Need redraw. */
-		tinput_display_tail(ti, 0, 0);
-	} else {
-		/* Shift not held. Keep selection empty. */
-		ti->sel_start = ti->pos;
-	}
-
-	tinput_position_caret(ti);
-}
-
-static void tinput_history_insert(tinput_t *ti, char *str)
-{
-	if (ti->hnum < HISTORY_LEN) {
-		ti->hnum += 1;
-	} else {
-		if (ti->history[HISTORY_LEN] != NULL)
-			free(ti->history[HISTORY_LEN]);
-	}
-
-	size_t i;
-	for (i = ti->hnum; i > 1; i--)
-		ti->history[i] = ti->history[i - 1];
-
-	ti->history[1] = str_dup(str);
-
-	if (ti->history[0] != NULL) {
-		free(ti->history[0]);
-		ti->history[0] = NULL;
-	}
-}
-
-static void tinput_set_str(tinput_t *ti, const char *str)
-{
-	str_to_wstr(ti->buffer, INPUT_MAX_SIZE, str);
-	ti->nc = wstr_length(ti->buffer);
-	ti->pos = ti->nc;
-	ti->sel_start = ti->pos;
-}
-
-static void tinput_sel_get_bounds(tinput_t *ti, size_t *sa, size_t *sb)
-{
-	if (ti->sel_start < ti->pos) {
-		*sa = ti->sel_start;
-		*sb = ti->pos;
-	} else {
-		*sa = ti->pos;
-		*sb = ti->sel_start;
-	}
-}
-
-static bool tinput_sel_active(tinput_t *ti)
-{
-	return (ti->sel_start != ti->pos);
-}
-
-static void tinput_sel_all(tinput_t *ti)
-{
-	ti->sel_start = 0;
-	ti->pos = ti->nc;
-	tinput_display_tail(ti, 0, 0);
-	tinput_position_caret(ti);
-}
-
-static void tinput_sel_delete(tinput_t *ti)
-{
-	size_t sa;
-	size_t sb;
-
-	tinput_sel_get_bounds(ti, &sa, &sb);
-	if (sa == sb)
-		return;
-
-	memmove(ti->buffer + sa, ti->buffer + sb,
-	    (ti->nc - sb) * sizeof(char32_t));
-
-	ti->pos = ti->sel_start = sa;
-	ti->nc -= (sb - sa);
-	ti->buffer[ti->nc] = '\0';
-
-	tinput_display_tail(ti, sa, sb - sa);
-	tinput_position_caret(ti);
-}
-
-static void tinput_sel_copy_to_cb(tinput_t *ti)
-{
-	size_t sa;
-	size_t sb;
-
-	tinput_sel_get_bounds(ti, &sa, &sb);
-
-	char *str;
-
-	if (sb < ti->nc) {
-		char32_t tmp_c = ti->buffer[sb];
-		ti->buffer[sb] = '\0';
-		str = wstr_to_astr(ti->buffer + sa);
-		ti->buffer[sb] = tmp_c;
-	} else
-		str = wstr_to_astr(ti->buffer + sa);
-
-	if (str == NULL)
-		goto error;
-
-	if (clipboard_put_str(str) != EOK)
-		goto error;
-
-	free(str);
-	return;
-
-error:
-	/* TODO: Give the user some kind of warning. */
-	return;
-}
-
-static void tinput_paste_from_cb(tinput_t *ti)
-{
-	char *str;
-	errno_t rc = clipboard_get_str(&str);
-
-	if ((rc != EOK) || (str == NULL)) {
-		/* TODO: Give the user some kind of warning. */
-		return;
-	}
-
-	tinput_insert_string(ti, str);
-	free(str);
-}
-
-static void tinput_history_seek(tinput_t *ti, int offs)
-{
-	if (offs >= 0) {
-		if (ti->hpos + offs > ti->hnum)
-			return;
-	} else {
-		if (ti->hpos < (size_t) -offs)
-			return;
-	}
-
-	if (ti->history[ti->hpos] != NULL) {
-		free(ti->history[ti->hpos]);
-		ti->history[ti->hpos] = NULL;
-	}
-
-	ti->history[ti->hpos] = tinput_get_str(ti);
-	ti->hpos += offs;
-
-	int pad = (int) ti->nc - str_length(ti->history[ti->hpos]);
-	if (pad < 0)
-		pad = 0;
-
-	tinput_set_str(ti, ti->history[ti->hpos]);
-	tinput_display_tail(ti, 0, pad);
-	tinput_update_origin(ti);
-	tinput_position_caret(ti);
-}
-
-/** Compare two entries in array of completions. */
-static int compl_cmp(const void *va, const void *vb)
-{
-	const char *a = *(const char **) va;
-	const char *b = *(const char **) vb;
-
-	return str_cmp(a, b);
-}
-
-static size_t common_pref_len(const char *a, const char *b)
-{
-	size_t i;
-	size_t a_off, b_off;
-	char32_t ca, cb;
-
-	i = 0;
-	a_off = 0;
-	b_off = 0;
-
-	while (true) {
-		ca = str_decode(a, &a_off, STR_NO_LIMIT);
-		cb = str_decode(b, &b_off, STR_NO_LIMIT);
-
-		if (ca == '\0' || cb == '\0' || ca != cb)
-			break;
-		++i;
-	}
-
-	return i;
-}
-
-/* Print a list of completions */
-static void tinput_show_completions(tinput_t *ti, char **compl, size_t cnum)
-{
-	unsigned int i;
-	/* Determine the maximum width of the completion in chars */
-	size_t max_width = 0;
-	for (i = 0; i < cnum; i++)
-		max_width = max(max_width, str_width(compl[i]));
-
-	unsigned int cols = max(1, (ti->con_cols + 1) / (max_width + 1));
-	unsigned int padding = 0;
-	if (cols * max_width + (cols - 1) < ti->con_cols) {
-		padding = ti->con_cols - cols * max_width - (cols - 1);
-	}
-	unsigned int col_width = max_width + padding / cols;
-	unsigned int rows = cnum / cols + ((cnum % cols) != 0);
-
-	unsigned int row, col;
-
-	for (row = 0; row < rows; row++) {
-		unsigned int display_col = 0;
-		for (col = 0; col < cols; col++) {
-			size_t compl_idx = col * rows + row;
-			if (compl_idx >= cnum)
-				break;
-			if (col) {
-				printf(" ");
-				display_col++;
-			}
-			printf("%s", compl[compl_idx]);
-			size_t compl_width = str_width(compl[compl_idx]);
-			display_col += compl_width;
-			if (col < cols - 1) {
-				for (i = compl_width; i < col_width; i++) {
-					printf(" ");
-					display_col++;
-				}
-			}
-		}
-		if ((display_col % ti->con_cols) > 0)
-			printf("\n");
-	}
-	fflush(stdout);
-}
-
-static void tinput_text_complete(tinput_t *ti)
-{
-	void *state;
-	size_t cstart;
-	char *ctmp;
-	char **compl;     	/* Array of completions */
-	size_t compl_len;	/* Current length of @c compl array */
-	size_t cnum;
-	size_t i;
-	errno_t rc;
-
-	if (ti->compl_ops == NULL)
-		return;
-
-	/*
-	 * Obtain list of all possible completions (growing array).
-	 */
-
-	rc = (*ti->compl_ops->init)(ti->buffer, ti->pos, &cstart, &state);
-	if (rc != EOK)
-		return;
-
-	cnum = 0;
-
-	compl_len = 1;
-	compl = malloc(compl_len * sizeof(char *));
-	if (compl == NULL) {
-		printf("Error: Out of memory.\n");
-		return;
-	}
-
-	while (true) {
-		rc = (*ti->compl_ops->get_next)(state, &ctmp);
-		if (rc != EOK)
-			break;
-
-		if (cnum >= compl_len) {
-			/* Extend array */
-			compl_len = 2 * compl_len;
-			char **temp = realloc(compl, compl_len * sizeof(char *));
-			if (temp == NULL) {
-				free(compl);
-				printf("Error: Out of memory.\n");
-				break;
-			}
-			compl = temp;
-		}
-
-		compl[cnum] = str_dup(ctmp);
-		if (compl[cnum] == NULL) {
-			printf("Error: Out of memory.\n");
-			break;
-		}
-		cnum++;
-	}
-
-	(*ti->compl_ops->fini)(state);
-
-	if (cnum > 1) {
-		/*
-		 * More than one match. Determine maximum common prefix.
-		 */
-		size_t cplen;
-
-		cplen = str_length(compl[0]);
-		for (i = 1; i < cnum; i++)
-			cplen = min(cplen, common_pref_len(compl[0], compl[i]));
-
-		/* Compute how many bytes we should skip. */
-		size_t istart = str_lsize(compl[0], ti->pos - cstart);
-
-		if (cplen > istart) {
-			/* Insert common prefix. */
-
-			/* Copy remainder of common prefix. */
-			char *cpref = str_ndup(compl[0] + istart,
-			    str_lsize(compl[0], cplen - istart));
-
-			/* Insert it. */
-			tinput_insert_string(ti, cpref);
-			free(cpref);
-		} else {
-			/* No common prefix. Sort and display all entries. */
-
-			qsort(compl, cnum, sizeof(char *), compl_cmp);
-
-			tinput_jump_after(ti);
-			tinput_show_completions(ti, compl, cnum);
-			tinput_display(ti);
-		}
-	} else if (cnum == 1) {
-		/*
-		 * We have exactly one match. Insert it.
-		 */
-
-		/* Compute how many bytes of completion string we should skip. */
-		size_t istart = str_lsize(compl[0], ti->pos - cstart);
-
-		/* Insert remainder of completion string at current position. */
-		tinput_insert_string(ti, compl[0] + istart);
-	}
-
-	for (i = 0; i < cnum; i++)
-		free(compl[i]);
-	free(compl);
-}
-
-/** Initialize text input field.
- *
- * Must be called before using the field. It clears the history.
- */
-static void tinput_init(tinput_t *ti)
-{
-	ti->console = console_init(stdin, stdout);
-	ti->hnum = 0;
-	ti->hpos = 0;
-	ti->history[0] = NULL;
-}
-
-/** Set prompt string.
- *
- * @param ti		Text input
- * @param prompt	Prompt string
- *
- * @return		EOK on success, ENOMEM if out of memory.
- */
-errno_t tinput_set_prompt(tinput_t *ti, const char *prompt)
-{
-	if (ti->prompt != NULL)
-		free(ti->prompt);
-
-	ti->prompt = str_dup(prompt);
-	if (ti->prompt == NULL)
-		return ENOMEM;
-
-	return EOK;
-}
-
-/** Set completion ops.
- *
- * Set pointer to completion ops structure that will be used for text
- * completion.
- */
-void tinput_set_compl_ops(tinput_t *ti, tinput_compl_ops_t *compl_ops)
-{
-	ti->compl_ops = compl_ops;
-}
-
-/** Handle key press event. */
-static void tinput_key_press(tinput_t *ti, kbd_event_t *kev)
-{
-	if (kev->key == KC_LSHIFT)
-		ti->lshift_held = true;
-	if (kev->key == KC_RSHIFT)
-		ti->rshift_held = true;
-
-	if (((kev->mods & KM_CTRL) != 0) &&
-	    ((kev->mods & (KM_ALT | KM_SHIFT)) == 0))
-		tinput_key_ctrl(ti, kev);
-
-	if (((kev->mods & KM_SHIFT) != 0) &&
-	    ((kev->mods & (KM_CTRL | KM_ALT)) == 0))
-		tinput_key_shift(ti, kev);
-
-	if (((kev->mods & KM_CTRL) != 0) &&
-	    ((kev->mods & KM_SHIFT) != 0) &&
-	    ((kev->mods & KM_ALT) == 0))
-		tinput_key_ctrl_shift(ti, kev);
-
-	if ((kev->mods & (KM_CTRL | KM_ALT | KM_SHIFT)) == 0)
-		tinput_key_unmod(ti, kev);
-
-	if (((kev->mods & (KM_CTRL | KM_ALT)) == 0) && kev->c >= ' ') {
-		tinput_sel_delete(ti);
-		tinput_insert_char(ti, kev->c);
-	}
-}
-
-/** Handle key release event. */
-static void tinput_key_release(tinput_t *ti, kbd_event_t *kev)
-{
-	if (kev->key == KC_LSHIFT)
-		ti->lshift_held = false;
-	if (kev->key == KC_RSHIFT)
-		ti->rshift_held = false;
-}
-
-/** Position event */
-static void tinput_pos(tinput_t *ti, pos_event_t *ev)
-{
-	if (ev->type == POS_PRESS) {
-		tinput_seek_scrpos(ti, ev->hpos, ev->vpos,
-		    ti->lshift_held || ti->rshift_held);
-	}
-}
-
-/** Read in one line of input with initial text provided.
- *
- * @param ti   Text input
- * @param istr Initial string
- * @param dstr Place to save pointer to new string
- *
- * @return EOK on success
- * @return ENOENT if user requested abort
- * @return EIO if communication with console failed
- *
- */
-errno_t tinput_read_i(tinput_t *ti, const char *istr, char **dstr)
-{
-	errno_t rc;
-
-	console_flush(ti->console);
-	if (console_get_size(ti->console, &ti->con_cols, &ti->con_rows) != EOK)
-		return EIO;
-
-	tinput_set_str(ti, istr);
-
-	ti->sel_start = 0;
-	ti->done = false;
-	ti->exit_clui = false;
-
-	if (tinput_display(ti) != EOK)
-		return EIO;
-
-	while (!ti->done) {
-		console_flush(ti->console);
-
-		cons_event_t ev;
-		rc = console_get_event(ti->console, &ev);
-		if (rc != EOK)
-			return EIO;
-
-		switch (ev.type) {
-		case CEV_KEY:
-			if (ev.ev.key.type == KEY_PRESS)
-				tinput_key_press(ti, &ev.ev.key);
-			else
-				tinput_key_release(ti, &ev.ev.key);
-			break;
-		case CEV_POS:
-			tinput_pos(ti, &ev.ev.pos);
-			break;
-		}
-	}
-
-	if (ti->exit_clui)
-		return ENOENT;
-
-	ti->pos = ti->nc;
-	tinput_position_caret(ti);
-	putchar('\n');
-
-	char *str = tinput_get_str(ti);
-	if (str_cmp(str, "") != 0)
-		tinput_history_insert(ti, str);
-
-	ti->hpos = 0;
-
-	*dstr = str;
-	return EOK;
-}
-
-/** Read in one line of input.
- *
- * @param ti   Text input
- * @param dstr Place to save pointer to new string.
- *
- * @return EOK on success
- * @return ENOENT if user requested abort
- * @return EIO if communication with console failed
- *
- */
-errno_t tinput_read(tinput_t *ti, char **dstr)
-{
-	return tinput_read_i(ti, "", dstr);
-}
-
-static void tinput_key_ctrl(tinput_t *ti, kbd_event_t *ev)
-{
-	switch (ev->key) {
-	case KC_LEFT:
-		tinput_seek_word(ti, seek_backward, false);
-		break;
-	case KC_RIGHT:
-		tinput_seek_word(ti, seek_forward, false);
-		break;
-	case KC_UP:
-		tinput_seek_vertical(ti, seek_backward, false);
-		break;
-	case KC_DOWN:
-		tinput_seek_vertical(ti, seek_forward, false);
-		break;
-	case KC_X:
-		tinput_sel_copy_to_cb(ti);
-		tinput_sel_delete(ti);
-		break;
-	case KC_C:
-		tinput_sel_copy_to_cb(ti);
-		break;
-	case KC_V:
-		tinput_sel_delete(ti);
-		tinput_paste_from_cb(ti);
-		break;
-	case KC_A:
-		tinput_sel_all(ti);
-		break;
-	case KC_Q:
-		/* Signal libary client to quit interactive loop. */
-		ti->done = true;
-		ti->exit_clui = true;
-		break;
-	default:
-		break;
-	}
-}
-
-static void tinput_key_ctrl_shift(tinput_t *ti, kbd_event_t *ev)
-{
-	switch (ev->key) {
-	case KC_LEFT:
-		tinput_seek_word(ti, seek_backward, true);
-		break;
-	case KC_RIGHT:
-		tinput_seek_word(ti, seek_forward, true);
-		break;
-	case KC_UP:
-		tinput_seek_vertical(ti, seek_backward, true);
-		break;
-	case KC_DOWN:
-		tinput_seek_vertical(ti, seek_forward, true);
-		break;
-	default:
-		break;
-	}
-}
-
-static void tinput_key_shift(tinput_t *ti, kbd_event_t *ev)
-{
-	switch (ev->key) {
-	case KC_LEFT:
-		tinput_seek_cell(ti, seek_backward, true);
-		break;
-	case KC_RIGHT:
-		tinput_seek_cell(ti, seek_forward, true);
-		break;
-	case KC_UP:
-		tinput_seek_vertical(ti, seek_backward, true);
-		break;
-	case KC_DOWN:
-		tinput_seek_vertical(ti, seek_forward, true);
-		break;
-	case KC_HOME:
-		tinput_seek_max(ti, seek_backward, true);
-		break;
-	case KC_END:
-		tinput_seek_max(ti, seek_forward, true);
-		break;
-	default:
-		break;
-	}
-}
-
-static void tinput_key_unmod(tinput_t *ti, kbd_event_t *ev)
-{
-	switch (ev->key) {
-	case KC_ENTER:
-	case KC_NENTER:
-		ti->done = true;
-		break;
-	case KC_BACKSPACE:
-		tinput_backspace(ti);
-		break;
-	case KC_DELETE:
-		tinput_delete(ti);
-		break;
-	case KC_LEFT:
-		tinput_seek_cell(ti, seek_backward, false);
-		break;
-	case KC_RIGHT:
-		tinput_seek_cell(ti, seek_forward, false);
-		break;
-	case KC_HOME:
-		tinput_seek_max(ti, seek_backward, false);
-		break;
-	case KC_END:
-		tinput_seek_max(ti, seek_forward, false);
-		break;
-	case KC_UP:
-		tinput_history_seek(ti, 1);
-		break;
-	case KC_DOWN:
-		tinput_history_seek(ti, -1);
-		break;
-	case KC_TAB:
-		tinput_text_complete(ti);
-		break;
-	default:
-		break;
-	}
-}
-
-/**
- * @}
- */
Index: uspace/lib/clui/tinput.h
===================================================================
--- uspace/lib/clui/tinput.h	(revision 00e62883ce36dafecb81ee65875c0b6a4529130b)
+++ 	(revision )
@@ -1,165 +1,0 @@
-/*
- * Copyright (c) 2011 Jiri Svoboda
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistributions of source code must retain the above copyright
- *   notice, this list of conditions and the following disclaimer.
- * - Redistributions in binary form must reproduce the above copyright
- *   notice, this list of conditions and the following disclaimer in the
- *   documentation and/or other materials provided with the distribution.
- * - The name of the author may not be used to endorse or promote products
- *   derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-/** @addtogroup libclui
- * @{
- */
-/**
- * @file
- */
-
-#ifndef LIBCLUI_TINPUT_H_
-#define LIBCLUI_TINPUT_H_
-
-#include <inttypes.h>
-#include <io/console.h>
-#include <stdio.h>
-
-#define HISTORY_LEN     10
-#define INPUT_MAX_SIZE  1024
-
-/** Begin enumeration of text completions.
- *
- * When user requests text completion, tinput will call this function to start
- * text completion operation. @a *cstart should be set to the position
- * (character index) of the first character of the 'word' that is being
- * completed. The resulting text is obtained by replacing the range of text
- * starting at @a *cstart and ending at @a pos with the completion text.
- *
- * The function can pass information to the get_next and fini functions
- * via @a state. The init function allocates the state object and stores
- * a pointer to it to @a *state. The fini function destroys the state object.
- *
- * @param text		Current contents of edit buffer (null-terminated).
- * @param pos		Current caret position.
- * @param cstart	Output, position in text where completion begins from.
- * @param state		Output, pointer to a client state object.
- *
- * @return		EOK on success, error code on failure.
- */
-typedef errno_t (*tinput_compl_init_fn)(char32_t *text, size_t pos, size_t *cstart,
-    void **state);
-
-/** Obtain one text completion alternative.
- *
- * Upon success the function sets @a *compl to point to a string, the
- * completion text. The caller (Tinput) should not modify or free the text.
- * The pointer is only valid until the next invocation of any completion
- * function.
- *
- * @param state		Pointer to state object created by the init funtion.
- * @param compl		Output, the completion text, ownership retained.
- *
- * @return		EOK on success, error code on failure.
- */
-typedef errno_t (*tinput_compl_get_next_fn)(void *state, char **compl);
-
-/** Finish enumeration of text completions.
- *
- * The function must deallocate any state information allocated by the init
- * function or temporary data allocated by the get_next function.
- *
- * @param state		Pointer to state object created by the init funtion.
- */
-typedef void (*tinput_compl_fini_fn)(void *state);
-
-/** Text completion ops. */
-typedef struct {
-	tinput_compl_init_fn init;
-	tinput_compl_get_next_fn get_next;
-	tinput_compl_fini_fn fini;
-} tinput_compl_ops_t;
-
-/** Text input field (command line).
- *
- * Applications should treat this structure as opaque.
- */
-typedef struct {
-	/** Console */
-	console_ctrl_t *console;
-
-	/** Prompt string */
-	char *prompt;
-
-	/** Completion ops. */
-	tinput_compl_ops_t *compl_ops;
-
-	/** Buffer holding text currently being edited */
-	char32_t buffer[INPUT_MAX_SIZE + 1];
-
-	/** Linear position on screen where the prompt starts */
-	unsigned prompt_coord;
-	/** Linear position on screen where the text field starts */
-	unsigned text_coord;
-
-	/** Screen dimensions */
-	sysarg_t con_cols;
-	sysarg_t con_rows;
-
-	/** Number of characters in @c buffer */
-	size_t nc;
-
-	/** Caret position within buffer */
-	size_t pos;
-
-	/** Selection mark position within buffer */
-	size_t sel_start;
-
-	/** History (dynamically allocated strings) */
-	char *history[HISTORY_LEN + 1];
-
-	/** Number of entries in @c history, not counting [0] */
-	size_t hnum;
-
-	/** Current position in history */
-	size_t hpos;
-
-	/** @c true if finished with this line (return to caller) */
-	bool done;
-
-	/** @c true if user requested to abort interactive loop */
-	bool exit_clui;
-
-	/** @c true if left shift key is currently held */
-	bool lshift_held;
-
-	/** @c true if right shift key is currently held */
-	bool rshift_held;
-} tinput_t;
-
-extern tinput_t *tinput_new(void);
-extern errno_t tinput_set_prompt(tinput_t *, const char *);
-extern void tinput_set_compl_ops(tinput_t *, tinput_compl_ops_t *);
-extern void tinput_destroy(tinput_t *);
-extern errno_t tinput_read(tinput_t *, char **);
-extern errno_t tinput_read_i(tinput_t *, const char *, char **);
-
-#endif
-
-/** @}
- */
