You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

176 lines
2.8 KiB

  1. package readline
  2. const (
  3. VIM_NORMAL = iota
  4. VIM_INSERT
  5. VIM_VISUAL
  6. )
  7. type opVim struct {
  8. cfg *Config
  9. op *Operation
  10. vimMode int
  11. }
  12. func newVimMode(op *Operation) *opVim {
  13. ov := &opVim{
  14. cfg: op.cfg,
  15. op: op,
  16. }
  17. ov.SetVimMode(ov.cfg.VimMode)
  18. return ov
  19. }
  20. func (o *opVim) SetVimMode(on bool) {
  21. if o.cfg.VimMode && !on { // turn off
  22. o.ExitVimMode()
  23. }
  24. o.cfg.VimMode = on
  25. o.vimMode = VIM_INSERT
  26. }
  27. func (o *opVim) ExitVimMode() {
  28. o.vimMode = VIM_INSERT
  29. }
  30. func (o *opVim) IsEnableVimMode() bool {
  31. return o.cfg.VimMode
  32. }
  33. func (o *opVim) handleVimNormalMovement(r rune, readNext func() rune) (t rune, handled bool) {
  34. rb := o.op.buf
  35. handled = true
  36. switch r {
  37. case 'h':
  38. t = CharBackward
  39. case 'j':
  40. t = CharNext
  41. case 'k':
  42. t = CharPrev
  43. case 'l':
  44. t = CharForward
  45. case '0', '^':
  46. rb.MoveToLineStart()
  47. case '$':
  48. rb.MoveToLineEnd()
  49. case 'x':
  50. rb.Delete()
  51. if rb.IsCursorInEnd() {
  52. rb.MoveBackward()
  53. }
  54. case 'r':
  55. rb.Replace(readNext())
  56. case 'd':
  57. next := readNext()
  58. switch next {
  59. case 'd':
  60. rb.Erase()
  61. case 'w':
  62. rb.DeleteWord()
  63. case 'h':
  64. rb.Backspace()
  65. case 'l':
  66. rb.Delete()
  67. }
  68. case 'p':
  69. rb.Yank()
  70. case 'b', 'B':
  71. rb.MoveToPrevWord()
  72. case 'w', 'W':
  73. rb.MoveToNextWord()
  74. case 'e', 'E':
  75. rb.MoveToEndWord()
  76. case 'f', 'F', 't', 'T':
  77. next := readNext()
  78. prevChar := r == 't' || r == 'T'
  79. reverse := r == 'F' || r == 'T'
  80. switch next {
  81. case CharEsc:
  82. default:
  83. rb.MoveTo(next, prevChar, reverse)
  84. }
  85. default:
  86. return r, false
  87. }
  88. return t, true
  89. }
  90. func (o *opVim) handleVimNormalEnterInsert(r rune, readNext func() rune) (t rune, handled bool) {
  91. rb := o.op.buf
  92. handled = true
  93. switch r {
  94. case 'i':
  95. case 'I':
  96. rb.MoveToLineStart()
  97. case 'a':
  98. rb.MoveForward()
  99. case 'A':
  100. rb.MoveToLineEnd()
  101. case 's':
  102. rb.Delete()
  103. case 'S':
  104. rb.Erase()
  105. case 'c':
  106. next := readNext()
  107. switch next {
  108. case 'c':
  109. rb.Erase()
  110. case 'w':
  111. rb.DeleteWord()
  112. case 'h':
  113. rb.Backspace()
  114. case 'l':
  115. rb.Delete()
  116. }
  117. default:
  118. return r, false
  119. }
  120. o.EnterVimInsertMode()
  121. return
  122. }
  123. func (o *opVim) HandleVimNormal(r rune, readNext func() rune) (t rune) {
  124. switch r {
  125. case CharEnter, CharInterrupt:
  126. o.ExitVimMode()
  127. return r
  128. }
  129. if r, handled := o.handleVimNormalMovement(r, readNext); handled {
  130. return r
  131. }
  132. if r, handled := o.handleVimNormalEnterInsert(r, readNext); handled {
  133. return r
  134. }
  135. // invalid operation
  136. o.op.t.Bell()
  137. return 0
  138. }
  139. func (o *opVim) EnterVimInsertMode() {
  140. o.vimMode = VIM_INSERT
  141. }
  142. func (o *opVim) ExitVimInsertMode() {
  143. o.vimMode = VIM_NORMAL
  144. }
  145. func (o *opVim) HandleVim(r rune, readNext func() rune) rune {
  146. if o.vimMode == VIM_NORMAL {
  147. return o.HandleVimNormal(r, readNext)
  148. }
  149. if r == CharEsc {
  150. o.ExitVimInsertMode()
  151. return 0
  152. }
  153. switch o.vimMode {
  154. case VIM_INSERT:
  155. return r
  156. case VIM_VISUAL:
  157. }
  158. return r
  159. }