LineEditor.cpp 2.7 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394
  1. #include "LineEditor.h"
  2. #include "GlobalState.h"
  3. #include <stdio.h>
  4. #include <unistd.h>
  5. #include <ctype.h>
  6. LineEditor::LineEditor()
  7. {
  8. }
  9. LineEditor::~LineEditor()
  10. {
  11. }
  12. void LineEditor::add_to_history(const String& line)
  13. {
  14. if ((m_history.size() + 1) > m_history_capacity)
  15. m_history.take_first();
  16. m_history.append(line);
  17. }
  18. String LineEditor::get_line()
  19. {
  20. for (;;) {
  21. char keybuf[16];
  22. ssize_t nread = read(0, keybuf, sizeof(keybuf));
  23. // FIXME: exit()ing here is a bit off. Should communicate failure to caller somehow instead.
  24. if (nread == 0)
  25. exit(0);
  26. if (nread < 0) {
  27. if (errno == EINTR) {
  28. if (g.was_interrupted) {
  29. if (!m_buffer.is_empty())
  30. printf("^C");
  31. }
  32. g.was_interrupted = false;
  33. m_buffer.clear();
  34. putchar('\n');
  35. return String::empty();
  36. } else {
  37. perror("read failed");
  38. // FIXME: exit()ing here is a bit off. Should communicate failure to caller somehow instead.
  39. exit(2);
  40. }
  41. }
  42. for (ssize_t i = 0; i < nread; ++i) {
  43. char ch = keybuf[i];
  44. if (ch == 0)
  45. continue;
  46. if (ch == 8 || ch == g.termios.c_cc[VERASE]) {
  47. if (m_buffer.is_empty())
  48. continue;
  49. m_buffer.take_last();
  50. putchar(8);
  51. fflush(stdout);
  52. continue;
  53. }
  54. if (ch == g.termios.c_cc[VWERASE]) {
  55. bool has_seen_nonspace = false;
  56. while (!m_buffer.is_empty()) {
  57. if (isspace(m_buffer.last())) {
  58. if (has_seen_nonspace)
  59. break;
  60. } else {
  61. has_seen_nonspace = true;
  62. }
  63. putchar(0x8);
  64. m_buffer.take_last();
  65. }
  66. fflush(stdout);
  67. continue;
  68. }
  69. if (ch == g.termios.c_cc[VKILL]) {
  70. if (m_buffer.is_empty())
  71. continue;
  72. for (int i = 0; i < m_buffer.size(); ++i)
  73. putchar(0x8);
  74. m_buffer.clear();
  75. fflush(stdout);
  76. continue;
  77. }
  78. putchar(ch);
  79. fflush(stdout);
  80. if (ch != '\n') {
  81. m_buffer.append(ch);
  82. } else {
  83. auto string = String::copy(m_buffer);
  84. m_buffer.clear();
  85. return string;
  86. }
  87. }
  88. }
  89. }