+2021-02-08  Andrew Burgess  <andrew.burgess@embecosm.com>
+
+       * tui/tui-interp.c (tui_command_line_handler): New function.
+       (tui_interp::resume): Register tui_command_line_handler as the
+       input_handler.
+       * tui/tui-io.c (tui_inject_newline_into_command_window): New
+       function.
+       (tui_getc_1): Delete handling of '\n' and '\r'.
+       * tui-io.h (tui_inject_newline_into_command_window): Declare.
+
 2021-02-07  Hannes Domani  <ssbssa@yahoo.de>
 
        * tui/tui-regs.c (tui_data_window::display_registers_from):
 
+2021-02-08  Andrew Burgess  <andrew.burgess@embecosm.com>
+
+       * gdb.tui/scroll.exp: Tighten expected results.  Remove comment
+       about bug in GDB, update expected results, and add more tests.
+
 2021-02-08  Andrew Burgess  <andrew.burgess@embecosm.com>
 
        * gdb.tui/scroll.exp: New file.
 
 }
 
 # Now check that the contents of the command window are as expected.
-#
-# Well, we would if there wasn't a massive bug in GDB!!  The command
-# window contents will not be exactly what you'd expect after this
-# test has run.
-#
-# The expected output pattern given here is crafted so that it matches
-# those bits of the GDB output that will be correct, and ignores those
-# parts of the output that are known to be incorrect.
-#
-# If/when GDB is fixed it is expected that this test will continue to
-# pass, though it is possible that at that point the pattern here
-# could be improved.
 Term::check_region_contents "check cmd window" 0 16 80 8 \
     [multi_line \
-        "\[^\r\n\]*\\\$7 = 6\[^\r\n\]+" \
-        "\\(gdb\\)\[^\r\n\]+" \
-        "\[^\r\n\]*\\\$8 = 7\[^\r\n\]+" \
-        "\\(gdb\\)\[^\r\n\]+" \
-        "\[^\r\n\]*\\\$9 = 8\[^\r\n\]+" \
-        "\\(gdb\\)\[^\r\n\]+" \
-        "\[^\r\n\]*\\\$10 = 9\[^\r\n\]+" \
+        "\\\$7 = 6\\s+" \
+        "\\(gdb\\) p 7\\s+" \
+        "\\\$8 = 7\\s+" \
+        "\\(gdb\\) p 8\\s+" \
+        "\\\$9 = 8\\s+" \
+        "\\(gdb\\) p 9\\s+" \
+        "\\\$10 = 9\\s+" \
+        "\\(gdb\\)"]
+
+# Now create a new layout where the CMD window is at the top of the
+# screen.  Sitch to this layout and ensure that scrolling still works
+# as expected.
+Term::command "tui new-layout flip cmd 1 src 1"
+Term::command "layout flip"
+
+for {set i 10} {$i < 20} {incr i 1} {
+    Term::command "p $i"
+}
+
+# Now check that the contents of the command window are as expected.
+Term::check_region_contents "check cmd window in flip layout" 0 0 80 8 \
+    [multi_line \
+        "\\\$17 = 16\\s+" \
+        "\\(gdb\\) p 17\\s+" \
+        "\\\$18 = 17\\s+" \
+        "\\(gdb\\) p 18\\s+" \
+        "\\\$19 = 18\\s+" \
+        "\\(gdb\\) p 19\\s+" \
+        "\\\$20 = 19\\s+" \
         "\\(gdb\\)"]
 
     tui_ensure_readline_initialized ();
 }
 
+/* Used as the command handler for the tui.  */
+
+static void
+tui_command_line_handler (gdb::unique_xmalloc_ptr<char> &&rl)
+{
+  /* When a tui enabled GDB is running in either tui mode or cli mode then
+     it is always the tui interpreter that is in use.  As a result we end
+     up in here even in standard cli mode.
+
+     We only need to do any special actions when the tui is in use
+     though.  When the tui is active the users return is not echoed to the
+     screen as a result the display will not automatically move us to the
+     next line.  Here we manually insert a newline character and move the
+     cursor.  */
+  if (tui_active)
+    tui_inject_newline_into_command_window ();
+
+  /* Now perform GDB's standard CLI command line handling.  */
+  command_line_handler (std::move (rl));
+}
+
 void
 tui_interp::resume ()
 {
 
   gdb_setup_readline (1);
 
-  ui->input_handler = command_line_handler;
+  ui->input_handler = tui_command_line_handler;
 
   if (stream != NULL)
     tui_old_uiout->set_stream (gdb_stdout);
 
   return 0;
 }
 
+/* See tui-io.h.   */
+
+void
+tui_inject_newline_into_command_window ()
+{
+  gdb_assert (tui_active);
+
+  WINDOW *w= TUI_CMD_WIN->handle.get ();
+
+  /* When hitting return with an empty input, gdb executes the last
+     command.  If we emit a newline, this fills up the command window
+     with empty lines with gdb prompt at beginning.  Instead of that,
+     stay on the same line but provide a visual effect to show the
+     user we recognized the command.  */
+  if (rl_end == 0 && !gdb_in_secondary_prompt_p (current_ui))
+    {
+      wmove (w, getcury (w), 0);
+
+      /* Clear the line.  This will blink the gdb prompt since
+        it will be redrawn at the same line.  */
+      wclrtoeol (w);
+      wrefresh (w);
+      napms (20);
+    }
+  else
+    {
+      /* Move cursor to the end of the command line before emitting the
+        newline.  We need to do so because when ncurses outputs a newline
+        it truncates any text that appears past the end of the cursor.  */
+      int px, py;
+      getyx (w, py, px);
+      px += rl_end - rl_point;
+      py += px / TUI_CMD_WIN->width;
+      px %= TUI_CMD_WIN->width;
+      wmove (w, py, px);
+      tui_putc ('\n');
+    }
+}
+
 /* Main worker for tui_getc.  Get a character from the command window.
    This is called from the readline package, but wrapped in a
    try/catch by tui_getc.  */
 
   ch = gdb_wgetch (w);
 
-  /* The \n must be echoed because it will not be printed by
-     readline.  */
-  if (ch == '\n' || ch == '\r')
-    {
-      /* When hitting return with an empty input, gdb executes the last
-        command.  If we emit a newline, this fills up the command window
-        with empty lines with gdb prompt at beginning.  Instead of that,
-        stay on the same line but provide a visual effect to show the
-        user we recognized the command.  */
-      if (rl_end == 0 && !gdb_in_secondary_prompt_p (current_ui))
-       {
-         wmove (w, getcury (w), 0);
-
-         /* Clear the line.  This will blink the gdb prompt since
-            it will be redrawn at the same line.  */
-         wclrtoeol (w);
-         wrefresh (w);
-         napms (20);
-       }
-      else
-       {
-         /* Move cursor to the end of the command line before emitting the
-            newline.  We need to do so because when ncurses outputs a newline
-            it truncates any text that appears past the end of the cursor.  */
-         int px, py;
-         getyx (w, py, px);
-         px += rl_end - rl_point;
-         py += px / TUI_CMD_WIN->width;
-         px %= TUI_CMD_WIN->width;
-         wmove (w, py, px);
-         tui_putc ('\n');
-       }
-    }
-  
   /* Handle prev/next/up/down here.  */
   ch = tui_dispatch_ctrl_char (ch);
   
 
 extern struct ui_out *tui_out;
 extern cli_ui_out *tui_old_uiout;
 
+/* This should be called when the user has entered a command line in tui
+   mode.  Inject the newline into the output and move the cursor to the
+   next line.  */
+extern void tui_inject_newline_into_command_window ();
+
 #endif /* TUI_TUI_IO_H */