Index: uspace/app/edit/edit.c
===================================================================
--- uspace/app/edit/edit.c	(revision 80d8885598c0f6408d107f683d6e7f9bfefe2bf8)
+++ uspace/app/edit/edit.c	(revision dc5aa568a4c8addb5f59d28700a384a1570b43d0)
@@ -91,5 +91,5 @@
 typedef struct {
 	char *file_name;
-	sheet_t sh;
+	sheet_t *sh;
 } doc_t;
 
@@ -175,4 +175,5 @@
 	coord_t coord;
 	bool new_file;
+	int rc;
 
 	spt_t pt;
@@ -189,10 +190,14 @@
 
 	/* Start with an empty sheet. */
-	sheet_init(&doc.sh);
+	rc = sheet_create(&doc.sh);
+	if (rc != EOK) {
+		printf("Out of memory.\n");
+		return -1;
+	}
 
 	/* Place caret at the beginning of file. */
 	coord.row = coord.column = 1;
-	sheet_get_cell_pt(&doc.sh, &coord, dir_before, &pt);
-	sheet_place_tag(&doc.sh, &pt, &pane.caret_pos);
+	sheet_get_cell_pt(doc.sh, &coord, dir_before, &pt);
+	sheet_place_tag(doc.sh, &pt, &pane.caret_pos);
 	pane.ideal_column = coord.column;
 
@@ -216,5 +221,5 @@
 	/* Place selection start tag. */
 	tag_get_pt(&pane.caret_pos, &pt);
-	sheet_place_tag(&doc.sh, &pt, &pane.sel_start);
+	sheet_place_tag(doc.sh, &pt, &pane.sel_start);
 
 	/* Initial display */
@@ -447,7 +452,7 @@
 	if (select == false) {
 		/* Move sel_start to the same point as caret. */
-		sheet_remove_tag(&doc.sh, &pane.sel_start);
+		sheet_remove_tag(doc.sh, &pane.sel_start);
 		tag_get_pt(&pane.caret_pos, &pt);
-		sheet_place_tag(&doc.sh, &pt, &pane.sel_start);
+		sheet_place_tag(doc.sh, &pt, &pane.sel_start);
 	}
 
@@ -670,5 +675,5 @@
 
 	do {
-		sheet_copy_out(&doc.sh, &sp, epos, buf, BUF_SIZE, &bep);
+		sheet_copy_out(doc.sh, &sp, epos, buf, BUF_SIZE, &bep);
 		bytes = str_size(buf);
 
@@ -705,5 +710,5 @@
 
 	while (true) {
-		sheet_copy_out(&doc.sh, &sp, epos, &buf[bpos], buf_size - bpos,
+		sheet_copy_out(doc.sh, &sp, epos, &buf[bpos], buf_size - bpos,
 		    &bep);
 		bytes = str_size(&buf[bpos]);
@@ -727,5 +732,5 @@
 	int sh_rows, rows;
 
-	sheet_get_num_rows(&doc.sh, &sh_rows);
+	sheet_get_num_rows(doc.sh, &sh_rows);
 	rows = min(sh_rows - pane.sh_row + 1, pane.rows);
 
@@ -797,13 +802,13 @@
 		rbc.row = pane.sh_row + i;
 		rbc.column = pane.sh_column;
-		sheet_get_cell_pt(&doc.sh, &rbc, dir_before, &rb);
+		sheet_get_cell_pt(doc.sh, &rbc, dir_before, &rb);
 
 		/* Ending point for row display */
 		rec.row = pane.sh_row + i;
 		rec.column = pane.sh_column + pane.columns;
-		sheet_get_cell_pt(&doc.sh, &rec, dir_before, &re);
+		sheet_get_cell_pt(doc.sh, &rec, dir_before, &re);
 
 		/* Copy the text of the row to the buffer. */
-		sheet_copy_out(&doc.sh, &rb, &re, row_buf, ROW_BUF_SIZE, &dep);
+		sheet_copy_out(doc.sh, &rb, &re, row_buf, ROW_BUF_SIZE, &dep);
 
 		/* Display text from the buffer. */
@@ -874,14 +879,17 @@
 	spt_t caret_pt;
 	coord_t coord;
+	int last_row;
 
 	tag_get_pt(&pane.caret_pos, &caret_pt);
 	spt_get_coord(&caret_pt, &coord);
 
+	sheet_get_num_rows(doc.sh, &last_row);
+
 	const char *fname = (doc.file_name != NULL) ? doc.file_name : "<unnamed>";
 
 	console_set_pos(con, 0, scr_rows - 1);
 	console_set_style(con, STYLE_INVERTED);
-	int n = printf(" %d, %d: File '%s'. Ctrl-Q Quit  Ctrl-S Save  "
-	    "Ctrl-E Save As", coord.row, coord.column, fname);
+	int n = printf(" %d, %d (%d): File '%s'. Ctrl-Q Quit  Ctrl-S Save  "
+	    "Ctrl-E Save As", coord.row, coord.column, last_row, fname);
 	
 	int pos = scr_columns - 1 - n;
@@ -919,5 +927,5 @@
 	cbuf[offs] = '\0';
 
-	(void) sheet_insert(&doc.sh, &pt, dir_before, cbuf);
+	(void) sheet_insert(doc.sh, &pt, dir_before, cbuf);
 
 	pane.rflags |= REDRAW_ROW;
@@ -936,7 +944,7 @@
 
 	coord.column -= 1;
-	sheet_get_cell_pt(&doc.sh, &coord, dir_before, &sp);
-
-	(void) sheet_delete(&doc.sh, &sp, &ep);
+	sheet_get_cell_pt(doc.sh, &coord, dir_before, &sp);
+
+	(void) sheet_delete(doc.sh, &sp, &ep);
 
 	pane.rflags |= REDRAW_ROW;
@@ -954,8 +962,8 @@
 	spt_get_coord(&sp, &sc);
 
-	sheet_get_cell_pt(&doc.sh, &sc, dir_after, &ep);
+	sheet_get_cell_pt(doc.sh, &sc, dir_after, &ep);
 	spt_get_coord(&ep, &ec);
 
-	(void) sheet_delete(&doc.sh, &sp, &ep);
+	(void) sheet_delete(doc.sh, &sp, &ep);
 
 	pane.rflags |= REDRAW_ROW;
@@ -1029,9 +1037,9 @@
 		else {
 			coord.row--;
-			sheet_get_row_width(&doc.sh, coord.row, &coord.column);
+			sheet_get_row_width(doc.sh, coord.row, &coord.column);
 		}
 	}
 	if (drow > 0) {
-		sheet_get_num_rows(&doc.sh, &num_rows);
+		sheet_get_num_rows(doc.sh, &num_rows);
 		if (coord.row > num_rows) coord.row = num_rows;
 	}
@@ -1046,7 +1054,7 @@
 	 * coordinates. The character can be wider than one cell (e.g. tab).
 	 */
-	sheet_get_cell_pt(&doc.sh, &coord, align_dir, &pt);
-	sheet_remove_tag(&doc.sh, &pane.caret_pos);
-	sheet_place_tag(&doc.sh, &pt, &pane.caret_pos);
+	sheet_get_cell_pt(doc.sh, &coord, align_dir, &pt);
+	sheet_remove_tag(doc.sh, &pane.caret_pos);
+	sheet_place_tag(doc.sh, &pt, &pane.caret_pos);
 
 	/* For non-vertical movement set the new value for @c ideal_column. */
@@ -1068,6 +1076,6 @@
 		tag_get_pt(&pane.caret_pos, &pt);
 
-		sheet_remove_tag(&doc.sh, &pane.sel_start);
-		sheet_place_tag(&doc.sh, &pt, &pane.sel_start);
+		sheet_remove_tag(doc.sh, &pane.sel_start);
+		sheet_place_tag(doc.sh, &pt, &pane.sel_start);
 	} while (!pt_is_word_beginning(&pt));
 
@@ -1084,6 +1092,6 @@
 		tag_get_pt(&pane.caret_pos, &pt);
 
-		sheet_remove_tag(&doc.sh, &pane.sel_start);
-		sheet_place_tag(&doc.sh, &pt, &pane.sel_start);
+		sheet_remove_tag(doc.sh, &pane.sel_start);
+		sheet_place_tag(doc.sh, &pt, &pane.sel_start);
 	} while (!pt_is_word_beginning(&pt));
 
@@ -1163,7 +1171,7 @@
 
 	if (rel < 0)
-		sheet_delete(&doc.sh, &pa, &pb);
+		sheet_delete(doc.sh, &pa, &pb);
 	else
-		sheet_delete(&doc.sh, &pb, &pa);
+		sheet_delete(doc.sh, &pb, &pa);
 
 	if (ca.row == cb.row)
@@ -1187,8 +1195,8 @@
 static void selection_sel_range(spt_t pa, spt_t pb)
 {
-	sheet_remove_tag(&doc.sh, &pane.sel_start);
-	sheet_place_tag(&doc.sh, &pa, &pane.sel_start);
-	sheet_remove_tag(&doc.sh, &pane.caret_pos);
-	sheet_place_tag(&doc.sh, &pb, &pane.caret_pos);
+	sheet_remove_tag(doc.sh, &pane.sel_start);
+	sheet_place_tag(doc.sh, &pa, &pane.sel_start);
+	sheet_remove_tag(doc.sh, &pane.caret_pos);
+	sheet_place_tag(doc.sh, &pb, &pane.caret_pos);
 
 	pane.rflags |= REDRAW_TEXT;
@@ -1273,5 +1281,5 @@
 
 	coord.row = coord.column = 1;
-	sheet_get_cell_pt(&doc.sh, &coord, dir_before, pt);
+	sheet_get_cell_pt(doc.sh, &coord, dir_before, pt);
 }
 
@@ -1282,9 +1290,9 @@
 	int num_rows;
 
-	sheet_get_num_rows(&doc.sh, &num_rows);
+	sheet_get_num_rows(doc.sh, &num_rows);
 	coord.row = num_rows + 1;
 	coord.column = 1;
 
-	sheet_get_cell_pt(&doc.sh, &coord, dir_after, pt);
+	sheet_get_cell_pt(doc.sh, &coord, dir_after, pt);
 }
 
@@ -1297,5 +1305,5 @@
 	coord.column = 1;
 
-	sheet_get_cell_pt(&doc.sh, &coord, dir_before, spt);
+	sheet_get_cell_pt(doc.sh, &coord, dir_before, spt);
 }
 
@@ -1307,8 +1315,8 @@
 
 	spt_get_coord(cpt, &coord);
-	sheet_get_row_width(&doc.sh, coord.row, &row_width);
+	sheet_get_row_width(doc.sh, coord.row, &row_width);
 	coord.column = row_width - 1;
 
-	sheet_get_cell_pt(&doc.sh, &coord, dir_after, ept);
+	sheet_get_cell_pt(doc.sh, &coord, dir_after, ept);
 }
 
@@ -1336,5 +1344,5 @@
 
 	coord.column -= 1;
-	sheet_get_cell_pt(&doc.sh, &coord, dir_before, &lp);
+	sheet_get_cell_pt(doc.sh, &coord, dir_before, &lp);
 
 	return pt_is_delimiter(&lp)
@@ -1358,5 +1366,5 @@
 
 	coord.column += 1;
-	sheet_get_cell_pt(&doc.sh, &coord, dir_after, &rp);
+	sheet_get_cell_pt(doc.sh, &coord, dir_after, &rp);
 
 	ch = range_get_str(pt, &rp);
@@ -1384,5 +1392,5 @@
 
 	coord.column += 1;
-	sheet_get_cell_pt(&doc.sh, &coord, dir_after, &rp);
+	sheet_get_cell_pt(doc.sh, &coord, dir_after, &rp);
 
 	ch = range_get_str(pt, &rp);
Index: uspace/app/edit/sheet.c
===================================================================
--- uspace/app/edit/sheet.c	(revision 80d8885598c0f6408d107f683d6e7f9bfefe2bf8)
+++ uspace/app/edit/sheet.c	(revision dc5aa568a4c8addb5f59d28700a384a1570b43d0)
@@ -57,4 +57,5 @@
 
 #include "sheet.h"
+#include "sheet_impl.h"
 
 enum {
@@ -66,6 +67,12 @@
 
 /** Initialize an empty sheet. */
-int sheet_init(sheet_t *sh)
-{
+int sheet_create(sheet_t **rsh)
+{
+	sheet_t *sh;
+
+	sh = calloc(1, sizeof(sheet_t));
+	if (sh == NULL)
+		return ENOMEM;
+
 	sh->dbuf_size = INITIAL_SIZE;
 	sh->text_size = 0;
@@ -77,4 +84,5 @@
 	list_initialize(&sh->tags);
 
+	*rsh = sh;
 	return EOK;
 }
Index: uspace/app/edit/sheet.h
===================================================================
--- uspace/app/edit/sheet.h	(revision 80d8885598c0f6408d107f683d6e7f9bfefe2bf8)
+++ uspace/app/edit/sheet.h	(revision dc5aa568a4c8addb5f59d28700a384a1570b43d0)
@@ -50,13 +50,6 @@
 
 /** Sheet */
-typedef struct {
-	/* Note: This structure is opaque for the user. */
-
-	size_t text_size;
-	size_t dbuf_size;
-	char *data;
-
-	list_t tags;
-} sheet_t;
+struct sheet;
+typedef struct sheet sheet_t;
 
 /** Character cell coordinates
@@ -97,5 +90,5 @@
 } tag_t;
 
-extern int sheet_init(sheet_t *);
+extern int sheet_create(sheet_t **);
 extern int sheet_insert(sheet_t *, spt_t *, enum dir_spec, char *);
 extern int sheet_delete(sheet_t *, spt_t *, spt_t *);
Index: uspace/app/edit/sheet_impl.h
===================================================================
--- uspace/app/edit/sheet_impl.h	(revision dc5aa568a4c8addb5f59d28700a384a1570b43d0)
+++ uspace/app/edit/sheet_impl.h	(revision dc5aa568a4c8addb5f59d28700a384a1570b43d0)
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2012 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 edit
+ * @{
+ */
+/**
+ * @file
+ */
+
+#ifndef SHEET_IMPL_H__
+#define SHEET_IMPL_H__
+
+#include "sheet.h"
+
+/** Sheet */
+typedef struct sheet {
+	/* Note: This structure is opaque for the user. */
+
+	size_t text_size;
+	size_t dbuf_size;
+	char *data;
+
+	list_t tags;
+} sheet_t;
+
+#endif
+
+/** @}
+ */
Index: uspace/lib/c/generic/str.c
===================================================================
--- uspace/lib/c/generic/str.c	(revision 80d8885598c0f6408d107f683d6e7f9bfefe2bf8)
+++ uspace/lib/c/generic/str.c	(revision dc5aa568a4c8addb5f59d28700a384a1570b43d0)
@@ -397,4 +397,31 @@
 	
 	return len;
+}
+
+/** Get character display width on a character cell display.
+ *
+ * @param ch	Character
+ * @return	Width of character in cells.
+ */
+size_t chr_width(wchar_t ch)
+{
+	return 1;
+}
+
+/** Get string display width on a character cell display.
+ *
+ * @param str	String
+ * @return	Width of string in cells.
+ */
+size_t str_width(const char *str)
+{
+	size_t width = 0;
+	size_t offset = 0;
+	wchar_t ch;
+	
+	while ((ch = str_decode(str, &offset, STR_NO_LIMIT)) != 0)
+		width += chr_width(ch);
+	
+	return width;
 }
 
Index: uspace/lib/c/include/str.h
===================================================================
--- uspace/lib/c/include/str.h	(revision 80d8885598c0f6408d107f683d6e7f9bfefe2bf8)
+++ uspace/lib/c/include/str.h	(revision dc5aa568a4c8addb5f59d28700a384a1570b43d0)
@@ -73,4 +73,7 @@
 extern size_t wstr_nlength(const wchar_t *str, size_t size);
 
+extern size_t chr_width(wchar_t ch);
+extern size_t str_width(const char *str);
+
 extern bool ascii_check(wchar_t ch);
 extern bool chr_check(wchar_t ch);
Index: uspace/lib/clui/tinput.c
===================================================================
--- uspace/lib/clui/tinput.c	(revision 80d8885598c0f6408d107f683d6e7f9bfefe2bf8)
+++ uspace/lib/clui/tinput.c	(revision dc5aa568a4c8addb5f59d28700a384a1570b43d0)
@@ -595,15 +595,15 @@
 {
 	unsigned int i;
-	/* Determine the maximum length of the completion in chars */
-	size_t max_length = 0;
+	/* Determine the maximum width of the completion in chars */
+	size_t max_width = 0;
 	for (i = 0; i < cnum; i++)
-		max_length = max(max_length, str_length(compl[i]));
-	
-	unsigned int cols = max(1, (ti->con_cols + 1) / (max_length + 1));
+		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_length) + (cols - 1) < ti->con_cols) {
-		padding = ti->con_cols - (cols * max_length) - (cols - 1);
-	}
-	unsigned int col_width = max_length + padding / cols;
+	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);
 	
@@ -611,24 +611,26 @@
 	
 	for (row = 0; row < rows; row++) {
-		bool wlc = false;
+		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)
+			if (col) {
 				printf(" ");
+				display_col++;
+			}
 			printf("%s", compl[compl_idx]);
-			size_t compl_len = str_length(compl[compl_idx]);
-			if (col == cols -1) {
-				wlc = (compl_len == max_length);
-			}
-			else {
-				for (i = compl_len; i < col_width; i++) {
+			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 (!wlc) printf("\n");
-	}
+		if ((display_col % ti->con_cols) > 0) printf("\n");
+	}
+	fflush(stdout);
 }
 
