diff -ruN tintin-1.99.5/src/cursor.c tintin-tabcompletion/src/cursor.c
--- tintin-1.99.5/src/cursor.c	2009-05-06 23:42:33.000000000 -0400
+++ tintin-tabcompletion/src/cursor.c	2009-06-09 01:48:27.000000000 -0400
@@ -395,6 +395,8 @@
 	gtd->macro_buf[0] = 0;
 	gtd->input_tmp[0] = 0;
 
+	kill_list(gtd->ses, LIST_TABCYCLE);
+
 	if (HAS_BIT(gtd->flags, TINTIN_FLAG_HISTORYSEARCH))
 	{
 		DEL_BIT(gtd->flags, TINTIN_FLAG_HISTORYSEARCH);
@@ -823,7 +825,7 @@
 	}
 	else if (gtd->input_len - gtd->input_cur + gtd->input_pos == gtd->ses->cols)
 	{
-		input_printf("\033[%dG%.2s\033%dG",  gtd->ses->cols - 1, &gtd->input_buf[gtd->input_cur + gtd->ses->cols - gtd->input_pos-2], gtd->input_pos+gtd->input_off);
+		input_printf("\033[%dG%.2s\033[%dG",  gtd->ses->cols - 1, &gtd->input_buf[gtd->input_cur + gtd->ses->cols - gtd->input_pos-2], gtd->input_pos+gtd->input_off);
 	}
 }
 
@@ -872,41 +874,14 @@
 	do_suspend(gtd->ses, "");
 }
 
-DO_CURSOR(cursor_tab)
+
+int cursor_tab_add(int input_now, int stop_after_first)
 {
 	char tab[BUFFER_SIZE];
 	struct listnode *node;
+	int result;
 
-	int input_now;
-
-	if (gtd->input_len == 0)
-	{
-		return;
-	}
-
-	input_now = gtd->input_len - 1;
-
-	while (input_now && gtd->input_buf[input_now] != ' ')
-	{
-		input_now--;
-	}
-
-	if (input_now != 0 && input_now == gtd->input_len - 1)
-	{
-		return;
-	}
-
-	if (input_now)
-	{
-		input_now++;
-	}
-
-	if (gtd->ses->list[LIST_TAB]->f_node == NULL)
-	{
-		cursor_auto_tab(arg);
-
-		return;
-	}
+	result = FALSE;
 
 	for (node = gtd->ses->list[LIST_TAB]->f_node ; node ; node = node->next)
 	{
@@ -914,51 +889,28 @@
 
 		if (is_abbrev(&gtd->input_buf[input_now], tab))
 		{
-			if (gtd->input_cur == gtd->input_len)
+			if (searchnode_list(gtd->ses->list[LIST_TABCYCLE], tab))
 			{
-				input_printf("\033[%dD\033[%dP%s", gtd->input_len - input_now, gtd->input_len - input_now, tab);
+				continue;
 			}
-			else
-			{
-				input_printf("\033[%dC\033[%dD\033[%dP%s", gtd->input_len - gtd->input_cur, gtd->input_len - input_now, gtd->input_len - input_now, tab);
-			}
-			strcpy(&gtd->input_buf[input_now], tab);
-
-			gtd->input_len = input_now + strlen(tab);
-			gtd->input_cur = gtd->input_len;
-			gtd->input_pos = gtd->input_len;
-
-			break;
+			addnode_list(gtd->ses->list[LIST_TABCYCLE], tab, "", "");
+			if (stop_after_first)
+				return TRUE;
+			result = TRUE;
 		}
 	}
+
+	return result;
 }
 
-DO_CURSOR(cursor_auto_tab)
+int cursor_auto_tab_add(int input_now, int stop_after_first)
 {
 	char tab[BUFFER_SIZE], buf[BUFFER_SIZE];
-	int input_now, scroll_cnt, line_cnt;
+	int scroll_cnt, line_cnt;
+	char *arg;
+	int result;
 
-	if (gtd->input_len == 0)
-	{
-		return;
-	}
-
-	input_now = gtd->input_len - 1;
-
-	while (input_now && gtd->input_buf[input_now] != ' ')
-	{
-		input_now--;
-	}
-
-	if (input_now != 0 && input_now == gtd->input_len - 1)
-	{
-		return;
-	}
-
-	if (input_now)
-	{
-		input_now++;
-	}
+	result = FALSE;
 
 	line_cnt = 0;
 
@@ -1000,21 +952,14 @@
 
 			if (!strncmp(tab, &gtd->input_buf[input_now], strlen(&gtd->input_buf[input_now])))
 			{
-				if (gtd->input_cur == gtd->input_len)
-				{
-					input_printf("\033[%dD\033[%dP%s", gtd->input_len - input_now, gtd->input_len - input_now, tab);
-				}
-				else
+				if (searchnode_list(gtd->ses->list[LIST_TABCYCLE], tab))
 				{
-					input_printf("\033[%dC\033[%dD\033[%dP%s", gtd->input_len - gtd->input_cur, gtd->input_len - input_now, gtd->input_len - input_now, tab);
+					continue;
 				}
-				strcpy(&gtd->input_buf[input_now], tab);
-
-				gtd->input_len = input_now + strlen(tab);
-				gtd->input_cur = gtd->input_len;
-				gtd->input_pos = gtd->input_len;
-
-				return;
+				addnode_list(gtd->ses->list[LIST_TABCYCLE], tab, "", "");
+				if (stop_after_first)
+					return TRUE;
+				result = TRUE;
 			}
 
 			if (*arg == ';')
@@ -1024,4 +969,197 @@
 		}
 	}
 	while (scroll_cnt != gtd->ses->scroll_row);
+
+	return result;
+}
+
+int cursor_hide_completion(int input_now)
+{
+	struct listnode *f_node;
+	struct listnode *l_node;
+	int len_change;
+
+	f_node = gtd->ses->list[LIST_TABCYCLE]->f_node;
+	l_node = gtd->ses->list[LIST_TABCYCLE]->l_node;
+
+	if (f_node && l_node && !strcmp(l_node->left, &gtd->input_buf[input_now]))
+	{
+		len_change = strlen(l_node->left) - strlen(f_node->left);
+		if (len_change > 0)
+		{
+			if (gtd->input_cur < gtd->input_len)
+				input_printf("\033[%dC", gtd->input_len - gtd->input_cur);
+			input_printf("\033[%dD\033[%dP", len_change, len_change);
+			gtd->input_len = gtd->input_len - len_change;
+			gtd->input_buf[gtd->input_len] = 0;
+			gtd->input_cur = gtd->input_len;
+			gtd->input_pos = gtd->input_pos;
+		}
+		return TRUE;
+	}
+
+	kill_list(gtd->ses, LIST_TABCYCLE);
+	return FALSE;
+}
+
+int cursor_show_completion(int input_now, int show_last_node)
+{
+	struct listnode *node;
+
+	node = show_last_node ? gtd->ses->list[LIST_TABCYCLE]->l_node : gtd->ses->list[LIST_TABCYCLE]->f_node;
+
+	if (!node)
+		return FALSE;
+
+	if (gtd->input_cur < gtd->input_len)
+		input_printf("\033[%dC", gtd->input_len - gtd->input_cur);
+	if (gtd->input_len > input_now)
+		input_printf("\033[%dD\033[%dP", gtd->input_len - input_now, gtd->input_len - input_now);
+	if (input_now + strlen(node->left) < gtd->ses->cols - 2)
+		input_printf("%s", node->left);
+	strcpy(&gtd->input_buf[input_now], node->left);
+
+	gtd->input_len = input_now + strlen(node->left);
+	gtd->input_cur = gtd->input_len;
+	gtd->input_pos = gtd->input_len;
+
+	cursor_check_line("");
+
+	return TRUE;
+}
+
+int cursor_calc_input_now(void)
+{
+	int input_now;
+
+	if (gtd->input_len == 0)
+		return -1;
+
+	for (input_now = gtd->input_len - 1; input_now && gtd->input_buf[input_now] != ' '; input_now--);
+
+	if (input_now != 0 && input_now == gtd->input_len - 1)
+		return -1;
+	
+	if (gtd->input_buf[input_now] == ' ')
+		input_now++;
+
+	return input_now;
+}
+
+DO_CURSOR(cursor_tab_reverse)
+{
+	int input_now;
+
+	input_now = cursor_calc_input_now();
+	if (input_now < 0)
+		return;
+
+	if (cursor_hide_completion(input_now))
+		deletenode_list(gtd->ses, gtd->ses->list[LIST_TABCYCLE]->l_node, LIST_TABCYCLE);
+
+	if (!gtd->ses->list[LIST_TABCYCLE]->f_node)
+	{
+		addnode_list(gtd->ses->list[LIST_TABCYCLE], &gtd->input_buf[input_now], "", "");
+
+		while (cursor_tab_add(input_now, FALSE));
+	}
+
+	cursor_show_completion(input_now, TRUE);
+}
+
+DO_CURSOR(cursor_tab)
+{
+	int input_now, tab_found;
+
+	input_now = cursor_calc_input_now();
+	if (input_now < 0)
+		return;
+
+	cursor_hide_completion(input_now);
+
+	if (!gtd->ses->list[LIST_TABCYCLE]->f_node)
+		addnode_list(gtd->ses->list[LIST_TABCYCLE], &gtd->input_buf[input_now], "", "");
+
+	tab_found = cursor_tab_add(input_now, TRUE);
+
+	cursor_show_completion(input_now, tab_found);
+}
+
+DO_CURSOR(cursor_auto_tab_reverse)
+{
+	int input_now;
+
+	input_now = cursor_calc_input_now();
+	if (input_now < 0)
+		return;
+
+	if (cursor_hide_completion(input_now))
+		deletenode_list(gtd->ses, gtd->ses->list[LIST_TABCYCLE]->l_node, LIST_TABCYCLE);
+
+	if (!gtd->ses->list[LIST_TABCYCLE]->f_node)
+	{
+		addnode_list(gtd->ses->list[LIST_TABCYCLE], &gtd->input_buf[input_now], "", "");
+
+		while (cursor_auto_tab_add(input_now, FALSE));
+	}
+
+	cursor_show_completion(input_now, TRUE);
+}
+
+DO_CURSOR(cursor_auto_tab)
+{
+	int input_now, tab_found;
+
+	input_now = cursor_calc_input_now();
+	if (input_now < 0)
+		return;
+
+	cursor_hide_completion(input_now);
+
+	if (!gtd->ses->list[LIST_TABCYCLE]->f_node)
+		addnode_list(gtd->ses->list[LIST_TABCYCLE], &gtd->input_buf[input_now], "", "");
+
+	tab_found = cursor_auto_tab_add(input_now, TRUE);
+
+	cursor_show_completion(input_now, tab_found);
+}
+
+DO_CURSOR(cursor_mixed_tab_reverse)
+{
+	int input_now;
+
+	input_now = cursor_calc_input_now();
+	if (input_now < 0)
+		return;
+
+	if (cursor_hide_completion(input_now))
+		deletenode_list(gtd->ses, gtd->ses->list[LIST_TABCYCLE]->l_node, LIST_TABCYCLE);
+
+	if (!gtd->ses->list[LIST_TABCYCLE]->f_node)
+	{
+		addnode_list(gtd->ses->list[LIST_TABCYCLE], &gtd->input_buf[input_now], "", "");
+
+		while (cursor_tab_add(input_now, FALSE));
+		while (cursor_auto_tab_add(input_now, FALSE));
+	}
+
+	cursor_show_completion(input_now, TRUE);
+}
+
+DO_CURSOR(cursor_mixed_tab)
+{
+	int input_now, tab_found;
+
+	input_now = cursor_calc_input_now();
+	if (input_now < 0)
+		return;
+
+	cursor_hide_completion(input_now);
+
+	if (!gtd->ses->list[LIST_TABCYCLE]->f_node)
+		addnode_list(gtd->ses->list[LIST_TABCYCLE], &gtd->input_buf[input_now], "", "");
+
+	tab_found = cursor_tab_add(input_now, TRUE) || cursor_auto_tab_add(input_now, TRUE);
+
+	cursor_show_completion(input_now, tab_found);
 }
diff -ruN tintin-1.99.5/src/tables.c tintin-tabcompletion/src/tables.c
--- tintin-1.99.5/src/tables.c	2009-05-13 18:08:51.000000000 -0400
+++ tintin-tabcompletion/src/tables.c	2009-06-09 01:58:52.000000000 -0400
@@ -135,6 +135,7 @@
 	{    "PROMPT",            "PROMPTS",            PRIORITY,    3,  LIST_FLAG_SHOW|LIST_FLAG_MESSAGE|LIST_FLAG_READ|LIST_FLAG_WRITE|LIST_FLAG_CLASS|LIST_FLAG_INHERIT },
 	{    "SUBSTITUTE",        "SUBSTITUTIONS",      PRIORITY,    3,  LIST_FLAG_SHOW|LIST_FLAG_MESSAGE|LIST_FLAG_READ|LIST_FLAG_WRITE|LIST_FLAG_CLASS|LIST_FLAG_INHERIT },
 	{    "TAB",               "TABS",               ALPHA,       1,  LIST_FLAG_SHOW|LIST_FLAG_MESSAGE|LIST_FLAG_READ|LIST_FLAG_WRITE|LIST_FLAG_CLASS|LIST_FLAG_INHERIT },
+	{    "TABCYCLE",          "TABCYCLE",           APPEND,      1,  LIST_FLAG_SHOW|LIST_FLAG_MESSAGE },
 	{    "TICKER",            "TICKERS",            ALPHA,       3,  LIST_FLAG_SHOW|LIST_FLAG_MESSAGE|LIST_FLAG_READ|LIST_FLAG_WRITE|LIST_FLAG_CLASS|LIST_FLAG_INHERIT },
 	{    "VARIABLE",          "VARIABLES",          ALPHA,       2,  LIST_FLAG_SHOW|LIST_FLAG_MESSAGE|LIST_FLAG_READ|LIST_FLAG_WRITE|LIST_FLAG_CLASS|LIST_FLAG_INHERIT }
 
@@ -571,9 +572,15 @@
 	},
 	{
 		"TAB",
-		"Tab completion on last word",
+		"Tab completion on last word, search forward",
 		"\t",
-		cursor_tab
+		cursor_mixed_tab
+	},
+	{
+		"SHIFT-TAB",
+		"Tab completion on last word, search backward",
+		"[Z",
+		cursor_mixed_tab_reverse
 	},
 	{
 		"ENTER",
@@ -666,12 +673,30 @@
 		cursor_suspend
 	},
 	{
-		"AUTO TAB",
-		"Tab completion from scrollback buffer",
+		"AUTO TAB FWD",
+		"Tab completion from scrollback buffer, forward",
 		"",
 		cursor_auto_tab
 	},
 	{
+		"AUTO TAB REV",
+		"Tab completion from scrollback buffer, backward",
+		"",
+		cursor_auto_tab_reverse
+	},
+	{
+		"TAB LIST FWD",
+		"Tab completion from tabs list, forward",
+		"",
+		cursor_tab
+	},
+	{
+		"TAB LIST REV",
+		"Tab completion from tabs list, backward",
+		"",
+		cursor_tab_reverse
+	},
+	{
 		"DELETE",
 		"Delete character at cursor",
 		"[3~",
diff -ruN tintin-1.99.5/src/tintin.h tintin-tabcompletion/src/tintin.h
--- tintin-1.99.5/src/tintin.h	2009-05-13 22:48:03.000000000 -0400
+++ tintin-tabcompletion/src/tintin.h	2009-06-09 01:21:23.000000000 -0400
@@ -168,9 +168,10 @@
 #define LIST_PROMPT                     15
 #define LIST_SUBSTITUTE                 16
 #define LIST_TAB                        17
-#define LIST_TICKER                     18
-#define LIST_VARIABLE                   19
-#define LIST_MAX                        20
+#define LIST_TABCYCLE                   18
+#define LIST_TICKER                     19
+#define LIST_VARIABLE                   20
+#define LIST_MAX                        21
 
 /*
 	Command type
@@ -861,8 +862,12 @@
 extern DO_CURSOR(cursor_right);
 extern DO_CURSOR(cursor_right_word);
 extern DO_CURSOR(cursor_suspend);
+extern DO_CURSOR(cursor_tab_reverse);
 extern DO_CURSOR(cursor_tab);
+extern DO_CURSOR(cursor_auto_tab_reverse);
 extern DO_CURSOR(cursor_auto_tab);
+extern DO_CURSOR(cursor_mixed_tab_reverse);
+extern DO_CURSOR(cursor_mixed_tab);
 
 
 #endif
