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.

165 lines
3.9 KiB

  1. package readline
  2. import (
  3. "bytes"
  4. "strings"
  5. )
  6. // Caller type for dynamic completion
  7. type DynamicCompleteFunc func(string) []string
  8. type PrefixCompleterInterface interface {
  9. Print(prefix string, level int, buf *bytes.Buffer)
  10. Do(line []rune, pos int) (newLine [][]rune, length int)
  11. GetName() []rune
  12. GetChildren() []PrefixCompleterInterface
  13. SetChildren(children []PrefixCompleterInterface)
  14. }
  15. type DynamicPrefixCompleterInterface interface {
  16. PrefixCompleterInterface
  17. IsDynamic() bool
  18. GetDynamicNames(line []rune) [][]rune
  19. }
  20. type PrefixCompleter struct {
  21. Name []rune
  22. Dynamic bool
  23. Callback DynamicCompleteFunc
  24. Children []PrefixCompleterInterface
  25. }
  26. func (p *PrefixCompleter) Tree(prefix string) string {
  27. buf := bytes.NewBuffer(nil)
  28. p.Print(prefix, 0, buf)
  29. return buf.String()
  30. }
  31. func Print(p PrefixCompleterInterface, prefix string, level int, buf *bytes.Buffer) {
  32. if strings.TrimSpace(string(p.GetName())) != "" {
  33. buf.WriteString(prefix)
  34. if level > 0 {
  35. buf.WriteString("├")
  36. buf.WriteString(strings.Repeat("─", (level*4)-2))
  37. buf.WriteString(" ")
  38. }
  39. buf.WriteString(string(p.GetName()) + "\n")
  40. level++
  41. }
  42. for _, ch := range p.GetChildren() {
  43. ch.Print(prefix, level, buf)
  44. }
  45. }
  46. func (p *PrefixCompleter) Print(prefix string, level int, buf *bytes.Buffer) {
  47. Print(p, prefix, level, buf)
  48. }
  49. func (p *PrefixCompleter) IsDynamic() bool {
  50. return p.Dynamic
  51. }
  52. func (p *PrefixCompleter) GetName() []rune {
  53. return p.Name
  54. }
  55. func (p *PrefixCompleter) GetDynamicNames(line []rune) [][]rune {
  56. var names = [][]rune{}
  57. for _, name := range p.Callback(string(line)) {
  58. names = append(names, []rune(name+" "))
  59. }
  60. return names
  61. }
  62. func (p *PrefixCompleter) GetChildren() []PrefixCompleterInterface {
  63. return p.Children
  64. }
  65. func (p *PrefixCompleter) SetChildren(children []PrefixCompleterInterface) {
  66. p.Children = children
  67. }
  68. func NewPrefixCompleter(pc ...PrefixCompleterInterface) *PrefixCompleter {
  69. return PcItem("", pc...)
  70. }
  71. func PcItem(name string, pc ...PrefixCompleterInterface) *PrefixCompleter {
  72. name += " "
  73. return &PrefixCompleter{
  74. Name: []rune(name),
  75. Dynamic: false,
  76. Children: pc,
  77. }
  78. }
  79. func PcItemDynamic(callback DynamicCompleteFunc, pc ...PrefixCompleterInterface) *PrefixCompleter {
  80. return &PrefixCompleter{
  81. Callback: callback,
  82. Dynamic: true,
  83. Children: pc,
  84. }
  85. }
  86. func (p *PrefixCompleter) Do(line []rune, pos int) (newLine [][]rune, offset int) {
  87. return doInternal(p, line, pos, line)
  88. }
  89. func Do(p PrefixCompleterInterface, line []rune, pos int) (newLine [][]rune, offset int) {
  90. return doInternal(p, line, pos, line)
  91. }
  92. func doInternal(p PrefixCompleterInterface, line []rune, pos int, origLine []rune) (newLine [][]rune, offset int) {
  93. line = runes.TrimSpaceLeft(line[:pos])
  94. goNext := false
  95. var lineCompleter PrefixCompleterInterface
  96. for _, child := range p.GetChildren() {
  97. childNames := make([][]rune, 1)
  98. childDynamic, ok := child.(DynamicPrefixCompleterInterface)
  99. if ok && childDynamic.IsDynamic() {
  100. childNames = childDynamic.GetDynamicNames(origLine)
  101. } else {
  102. childNames[0] = child.GetName()
  103. }
  104. for _, childName := range childNames {
  105. if len(line) >= len(childName) {
  106. if runes.HasPrefix(line, childName) {
  107. if len(line) == len(childName) {
  108. newLine = append(newLine, []rune{' '})
  109. } else {
  110. newLine = append(newLine, childName)
  111. }
  112. offset = len(childName)
  113. lineCompleter = child
  114. goNext = true
  115. }
  116. } else {
  117. if runes.HasPrefix(childName, line) {
  118. newLine = append(newLine, childName[len(line):])
  119. offset = len(line)
  120. lineCompleter = child
  121. }
  122. }
  123. }
  124. }
  125. if len(newLine) != 1 {
  126. return
  127. }
  128. tmpLine := make([]rune, 0, len(line))
  129. for i := offset; i < len(line); i++ {
  130. if line[i] == ' ' {
  131. continue
  132. }
  133. tmpLine = append(tmpLine, line[i:]...)
  134. return doInternal(lineCompleter, tmpLine, len(tmpLine), origLine)
  135. }
  136. if goNext {
  137. return doInternal(lineCompleter, nil, 0, origLine)
  138. }
  139. return
  140. }