Author: kate Date: Thu Jul 14 17:00:04 2016 New Revision: 275482 URL: http://llvm.org/viewvc/llvm-project?rev=275482&view=rev Log: Editing multi-line content in a terminal environment involves a lot of trade-offs. When LLDB's multi-line editing support was first introduced for expressions / REPL contexts the behavior was as follows:
* The Return key is treated as a line-break except at the end of the input buffer, where a completeness test is applied This worked well enough when writing code, and makes it trivial to insert new lines above code you've already typed. Just use cursor navigation to move up and type freely. Where it was awkward is that the gesture to insert a line break and end editing is conflated for most people. Sometimes you want Return to end the editing session and other times you want to insert a line break. This commit changes the behavior as follows: * The Return key is treated as the end of editing except at the end of the input buffer, where a completeness test is applied * The Meta+Return sequence is always treated as a line break. This is consistent with conventions in Facebook and elsewhere since Alt/Option+Return is often mapped to Meta+Return. The unfortunate exception is on macOS where this *can* be the case, but isn't by default. Sigh. Note that by design both before and after the patch pasting a Return character always introduces a line break. <rdar://problem/26886287> Modified: lldb/trunk/include/lldb/Host/Editline.h lldb/trunk/source/Host/common/Editline.cpp Modified: lldb/trunk/include/lldb/Host/Editline.h URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Host/Editline.h?rev=275482&r1=275481&r2=275482&view=diff ============================================================================== --- lldb/trunk/include/lldb/Host/Editline.h (original) +++ lldb/trunk/include/lldb/Host/Editline.h Thu Jul 14 17:00:04 2016 @@ -279,11 +279,15 @@ namespace lldb_private { /// Prompt implementation for EditLine. const char * Prompt(); - - /// Line break command used when return is pressed in multi-line mode. + + /// Line break command used when meta+return is pressed in multi-line mode. unsigned char BreakLineCommand (int ch); - + + /// Command used when return is pressed in multi-line mode. + unsigned char + EndOrAddLineCommand(int ch); + /// Delete command used when delete is pressed in multi-line mode. unsigned char DeleteNextCharCommand (int ch); @@ -299,7 +303,15 @@ namespace lldb_private { /// Line navigation command used when ^N or down arrow are pressed in multi-line mode. unsigned char NextLineCommand (int ch); - + + /// History navigation command used when Alt + up arrow is pressed in multi-line mode. + unsigned char + PreviousHistoryCommand(int ch); + + /// History navigation command used when Alt + down arrow is pressed in multi-line mode. + unsigned char + NextHistoryCommand(int ch); + /// Buffer start command used when Esc < is typed in multi-line emacs mode. unsigned char BufferStartCommand (int ch); Modified: lldb/trunk/source/Host/common/Editline.cpp URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Host/common/Editline.cpp?rev=275482&r1=275481&r2=275482&view=diff ============================================================================== --- lldb/trunk/source/Host/common/Editline.cpp (original) +++ lldb/trunk/source/Host/common/Editline.cpp Thu Jul 14 17:00:04 2016 @@ -657,41 +657,9 @@ Editline::BreakLineCommand (int ch) // Establish the new cursor position at the start of a line when inserting a line break m_revert_cursor_index = 0; - // Don't perform end of input detection or automatic formatting when pasting + // Don't perform automatic formatting when pasting if (!IsInputPending (m_input_file)) { - // If this is the end of the last line, treat this as a potential exit - if (m_current_line_index == m_input_lines.size() - 1 && new_line_fragment.length() == 0) - { - bool end_of_input = true; - if (m_is_input_complete_callback) - { - SaveEditedLine(); - auto lines = GetInputAsStringList(); - end_of_input = m_is_input_complete_callback (this, lines, m_is_input_complete_callback_baton); - - // The completion test is allowed to change the input lines when complete - if (end_of_input) - { - m_input_lines.clear(); - for (unsigned index = 0; index < lines.GetSize(); index++) - { -#if LLDB_EDITLINE_USE_WCHAR - m_input_lines.insert (m_input_lines.end(), m_utf8conv.from_bytes (lines[index])); -#else - m_input_lines.insert (m_input_lines.end(), lines[index]); -#endif - } - } - } - if (end_of_input) - { - fprintf (m_output_file, "\n"); - m_editor_status = EditorStatus::Complete; - return CC_NEWLINE; - } - } - // Apply smart indentation if (m_fix_indentation_callback) { @@ -720,7 +688,49 @@ Editline::BreakLineCommand (int ch) } unsigned char -Editline::DeleteNextCharCommand (int ch) +Editline::EndOrAddLineCommand(int ch) +{ + // Don't perform end of input detection when pasting, always treat this as a line break + if (IsInputPending(m_input_file)) + { + return BreakLineCommand(ch); + } + + // Save any edits to this line + SaveEditedLine(); + + // If this is the end of the last line, consider whether to add a line instead + const LineInfoW *info = el_wline(m_editline); + if (m_current_line_index == m_input_lines.size() - 1 && info->cursor == info->lastchar) + { + if (m_is_input_complete_callback) + { + auto lines = GetInputAsStringList(); + if (!m_is_input_complete_callback(this, lines, m_is_input_complete_callback_baton)) + { + return BreakLineCommand(ch); + } + + // The completion test is allowed to change the input lines when complete + m_input_lines.clear(); + for (unsigned index = 0; index < lines.GetSize(); index++) + { +#if LLDB_EDITLINE_USE_WCHAR + m_input_lines.insert(m_input_lines.end(), m_utf8conv.from_bytes(lines[index])); +#else + m_input_lines.insert(m_input_lines.end(), lines[index]); +#endif + } + } + } + MoveCursor(CursorLocation::EditingCursor, CursorLocation::BlockEnd); + fprintf(m_output_file, "\n"); + m_editor_status = EditorStatus::Complete; + return CC_NEWLINE; +} + +unsigned char +Editline::DeleteNextCharCommand(int ch) { LineInfoW * info = const_cast<LineInfoW *>(el_wline (m_editline)); @@ -860,7 +870,23 @@ Editline::NextLineCommand (int ch) } unsigned char -Editline::FixIndentationCommand (int ch) +Editline::PreviousHistoryCommand(int ch) +{ + SaveEditedLine(); + + return RecallHistory(true); +} + +unsigned char +Editline::NextHistoryCommand(int ch) +{ + SaveEditedLine(); + + return RecallHistory(false); +} + +unsigned char +Editline::FixIndentationCommand(int ch) { if (!m_fix_indentation_callback) return CC_NORM; @@ -1077,6 +1103,10 @@ Editline::ConfigureEditor (bool multilin el_wset(m_editline, EL_ADDFN, EditLineConstString("lldb-break-line"), EditLineConstString("Insert a line break"), (EditlineCommandCallbackType)( [](EditLine *editline, int ch) { return Editline::InstanceFor(editline)->BreakLineCommand(ch); })); + el_wset(m_editline, EL_ADDFN, EditLineConstString("lldb-end-or-add-line"), + EditLineConstString("End editing or continue when incomplete"), + (EditlineCommandCallbackType)( + [](EditLine *editline, int ch) { return Editline::InstanceFor(editline)->EndOrAddLineCommand(ch); })); el_wset(m_editline, EL_ADDFN, EditLineConstString("lldb-delete-next-char"), EditLineConstString("Delete next character"), (EditlineCommandCallbackType)([](EditLine *editline, int ch) { return Editline::InstanceFor(editline)->DeleteNextCharCommand(ch); @@ -1093,6 +1123,14 @@ Editline::ConfigureEditor (bool multilin el_wset(m_editline, EL_ADDFN, EditLineConstString("lldb-next-line"), EditLineConstString("Move to next line"), (EditlineCommandCallbackType)( [](EditLine *editline, int ch) { return Editline::InstanceFor(editline)->NextLineCommand(ch); })); + el_wset(m_editline, EL_ADDFN, EditLineConstString("lldb-previous-history"), + EditLineConstString("Move to previous history"), + (EditlineCommandCallbackType)([](EditLine *editline, int ch) { + return Editline::InstanceFor(editline)->PreviousHistoryCommand(ch); + })); + el_wset(m_editline, EL_ADDFN, EditLineConstString("lldb-next-history"), EditLineConstString("Move to next history"), + (EditlineCommandCallbackType)( + [](EditLine *editline, int ch) { return Editline::InstanceFor(editline)->NextHistoryCommand(ch); })); el_wset(m_editline, EL_ADDFN, EditLineConstString("lldb-buffer-start"), EditLineConstString("Move to start of buffer"), (EditlineCommandCallbackType)( @@ -1149,8 +1187,10 @@ Editline::ConfigureEditor (bool multilin // Multi-line editor bindings if (multiline) { - el_set (m_editline, EL_BIND, "\n", "lldb-break-line", NULL); - el_set (m_editline, EL_BIND, "\r", "lldb-break-line", NULL); + el_set(m_editline, EL_BIND, "\n", "lldb-end-or-add-line", NULL); + el_set(m_editline, EL_BIND, "\r", "lldb-end-or-add-line", NULL); + el_set(m_editline, EL_BIND, ESCAPE "\n", "lldb-break-line", NULL); + el_set(m_editline, EL_BIND, ESCAPE "\r", "lldb-break-line", NULL); el_set (m_editline, EL_BIND, "^p", "lldb-previous-line", NULL); el_set (m_editline, EL_BIND, "^n", "lldb-next-line", NULL); el_set (m_editline, EL_BIND, "^?", "lldb-delete-previous-char", NULL); @@ -1165,6 +1205,10 @@ Editline::ConfigureEditor (bool multilin el_set (m_editline, EL_BIND, ESCAPE ">", "lldb-buffer-end", NULL); el_set (m_editline, EL_BIND, ESCAPE "[A", "lldb-previous-line", NULL); el_set (m_editline, EL_BIND, ESCAPE "[B", "lldb-next-line", NULL); + el_set(m_editline, EL_BIND, ESCAPE ESCAPE "[A", "lldb-previous-history", NULL); + el_set(m_editline, EL_BIND, ESCAPE ESCAPE "[B", "lldb-next-history", NULL); + el_set(m_editline, EL_BIND, ESCAPE "[1;3A", "lldb-previous-history", NULL); + el_set(m_editline, EL_BIND, ESCAPE "[1;3B", "lldb-next-history", NULL); } else { _______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits