multiserver/console.go

190 lines
3.4 KiB
Go

package main
import (
"log"
"sort"
"strings"
"unicode/utf8"
"github.com/tncardoso/gocurses"
)
var consoleInput []rune
func draw(msgs []string) {
prompt, ok := ConfKey("console_prompt").(string)
if !ok {
prefix, ok := ConfKey("command_prefix").(string)
if !ok {
prefix = "#"
}
prompt = prefix + ">"
}
gocurses.Clear()
row, _ := gocurses.Getmaxyx()
i := len(msgs)
for _, msg := range msgs {
gocurses.Mvaddstr(row-i-1, 0, msg)
i--
}
gocurses.Mvaddstr(row-i-1, 0, prompt+string(consoleInput))
gocurses.Refresh()
}
func autoComplete(all []string, current string) string {
if len(all) > 1 && len(current) > 0 {
for k, v := range all {
if v == current {
if k+1 < len(all) {
return all[k+1]
} else {
return all[0]
}
}
}
} else if len(all) >= 1 {
return all[0]
}
return ""
}
func autoCompleteName(input []rune) []rune {
var name, tmpName []rune
for i := len(input) - 1; i >= 0; i-- {
if input[i] == ' ' {
input = input[:i+1]
break
}
tmpName = append(tmpName, input[i])
}
for i := len(tmpName) - 1; i >= 0; i-- {
name = append(name, tmpName[i])
}
var names []string
for _, c2 := range Conns() {
names = append(names, c2.Username())
}
return append(input, []rune(autoComplete(names, string(name)))...)
}
func autoCompleteCommand(input []rune) []rune {
var cmds []string
for cmd := range chatCommands {
if chatCommands[cmd].console {
cmds = append(cmds, cmd)
}
}
sort.Strings(cmds)
return []rune(autoComplete(cmds, string(input)))
}
func initCurses(l *Logger) {
gocurses.Initscr()
gocurses.Cbreak()
gocurses.Noecho()
gocurses.Stdscr.Keypad(true)
go func() {
h := &History{}
for {
var ch rune
ch1 := gocurses.Stdscr.Getch() % 255
if ch1 > 0x7F {
ch2 := gocurses.Stdscr.Getch()
ch, _ = utf8.DecodeRune([]byte{byte(ch1), byte(ch2)})
} else {
ch = rune(ch1)
}
switch ch {
case 3:
consoleInput = h.Next()
case 4:
consoleInput = h.Prev(consoleInput)
case '\b':
if len(consoleInput) > 0 {
consoleInput = consoleInput[:len(consoleInput)-1]
}
case '\t':
if strings.Count(string(consoleInput), " ") > 0 {
consoleInput = autoCompleteName(consoleInput)
} else {
consoleInput = autoCompleteCommand(consoleInput)
}
case '\n':
params := strings.Split(string(consoleInput), " ")
h.Add(consoleInput)
consoleInput = []rune{}
if chatCommands[params[0]].function == nil {
log.Print("Unknown command ", params[0])
continue
}
if !chatCommands[params[0]].console {
log.Print("This command is not available to the console!")
continue
}
chatCommands[params[0]].function(nil, strings.Join(params[1:], " "))
default:
consoleInput = append(consoleInput, ch)
}
draw(l.visible)
}
}()
}
type History struct {
lines [][]rune
i int
}
func (h *History) Add(line []rune) {
for k, v := range h.lines {
if string(v) == string(line) {
if k+1 < len(h.lines) {
h.lines = append(h.lines[:k], h.lines[k+1:]...)
} else {
h.lines = h.lines[:k]
}
}
}
h.lines = append(h.lines, line)
h.i = 0
}
func (h *History) Prev(current []rune) []rune {
h.i++
i := len(h.lines) - h.i
if i < 0 || i >= len(h.lines) {
h.i--
return current
}
return h.lines[i]
}
func (h *History) Next() []rune {
h.i--
if h.i < 1 {
h.i = 0
return []rune{}
}
return h.lines[len(h.lines)-h.i]
}