"github.com/mattn/go-runewidth"
"github.com/zyedidia/clipboard"
+ "github.com/zyedidia/micro/cmd/micro/shellwords"
"github.com/zyedidia/tcell"
)
}
}
+// Completion represents a type of completion
type Completion int
const (
event := <-events
switch e := event.(type) {
+ case *tcell.EventResize:
+ for _, t := range tabs {
+ t.Resize()
+ }
+ RedrawAll()
case *tcell.EventKey:
switch e.Key() {
case tcell.KeyCtrlQ, tcell.KeyCtrlC, tcell.KeyEscape:
response, canceled = m.response, false
m.history[historyType][len(m.history[historyType])-1] = response
case tcell.KeyTab:
- args := SplitCommandArgs(m.response)
- currentArgNum := len(args) - 1
- currentArg := args[currentArgNum]
+ args, err := shellwords.Split(m.response)
+ if err != nil {
+ break
+ }
+ currentArg := ""
+ currentArgNum := 0
+ if len(args) > 0 {
+ currentArgNum = len(args) - 1
+ currentArg = args[currentArgNum]
+ }
var completionType Completion
if completionTypes[0] == CommandCompletion && currentArgNum > 0 {
chosen = chosen + CommonSubstring(suggestions...)
}
- if chosen != "" {
- m.response = JoinCommandArgs(append(args[:len(args)-1], chosen)...)
+ if len(suggestions) != 0 && chosen != "" {
+ m.response = shellwords.Join(append(args[:len(args)-1], chosen)...)
m.cursorx = Count(m.response)
}
}
m.HandleEvent(event, m.history[historyType])
m.Clear()
- for _, v := range tabs[curTab].views {
+ for _, v := range tabs[curTab].Views {
v.Display()
}
DisplayTabs()
return response, canceled
}
+// UpHistory fetches the previous item in the history
+func (m *Messenger) UpHistory(history []string) {
+ if m.historyNum > 0 {
+ m.historyNum--
+ m.response = history[m.historyNum]
+ m.cursorx = Count(m.response)
+ }
+}
+
+// DownHistory fetches the next item in the history
+func (m *Messenger) DownHistory(history []string) {
+ if m.historyNum < len(history)-1 {
+ m.historyNum++
+ m.response = history[m.historyNum]
+ m.cursorx = Count(m.response)
+ }
+}
+
+// CursorLeft moves the cursor one character left
+func (m *Messenger) CursorLeft() {
+ if m.cursorx > 0 {
+ m.cursorx--
+ }
+}
+
+// CursorRight moves the cursor one character right
+func (m *Messenger) CursorRight() {
+ if m.cursorx < Count(m.response) {
+ m.cursorx++
+ }
+}
+
+// Start moves the cursor to the start of the line
+func (m *Messenger) Start() {
+ m.cursorx = 0
+}
+
+// End moves the cursor to the end of the line
+func (m *Messenger) End() {
+ m.cursorx = Count(m.response)
+}
+
+// Backspace deletes one character
+func (m *Messenger) Backspace() {
+ if m.cursorx > 0 {
+ m.response = string([]rune(m.response)[:m.cursorx-1]) + string([]rune(m.response)[m.cursorx:])
+ m.cursorx--
+ }
+}
+
+// Paste pastes the clipboard
+func (m *Messenger) Paste() {
+ clip, _ := clipboard.ReadAll("clipboard")
+ m.response = Insert(m.response, m.cursorx, clip)
+ m.cursorx += Count(clip)
+}
+
+// WordLeft moves the cursor one word to the left
+func (m *Messenger) WordLeft() {
+ response := []rune(m.response)
+ m.CursorLeft()
+ if m.cursorx <= 0 {
+ return
+ }
+ for IsWhitespace(response[m.cursorx]) {
+ if m.cursorx <= 0 {
+ return
+ }
+ m.CursorLeft()
+ }
+ m.CursorLeft()
+ for IsWordChar(string(response[m.cursorx])) {
+ if m.cursorx <= 0 {
+ return
+ }
+ m.CursorLeft()
+ }
+ m.CursorRight()
+}
+
+// WordRight moves the cursor one word to the right
+func (m *Messenger) WordRight() {
+ response := []rune(m.response)
+ if m.cursorx >= len(response) {
+ return
+ }
+ for IsWhitespace(response[m.cursorx]) {
+ m.CursorRight()
+ if m.cursorx >= len(response) {
+ m.CursorRight()
+ return
+ }
+ }
+ m.CursorRight()
+ if m.cursorx >= len(response) {
+ return
+ }
+ for IsWordChar(string(response[m.cursorx])) {
+ m.CursorRight()
+ if m.cursorx >= len(response) {
+ return
+ }
+ }
+}
+
+// DeleteWordLeft deletes one word to the left
+func (m *Messenger) DeleteWordLeft() {
+ m.WordLeft()
+ m.response = string([]rune(m.response)[:m.cursorx])
+}
+
// HandleEvent handles an event for the prompter
func (m *Messenger) HandleEvent(event tcell.Event, history []string) {
switch e := event.(type) {
case *tcell.EventKey:
- if e.Key() != tcell.KeyRune || e.Modifiers() != 0 {
- for key, actions := range bindings {
- if e.Key() == key.keyCode {
- if e.Key() == tcell.KeyRune {
- if e.Rune() != key.r {
- continue
- }
- }
- if e.Modifiers() == key.modifiers {
- for _, action := range actions {
- funcName := FuncName(action)
- switch funcName {
- case "main.(*View).CursorUp":
- if m.historyNum > 0 {
- m.historyNum--
- m.response = history[m.historyNum]
- m.cursorx = Count(m.response)
- }
- case "main.(*View).CursorDown":
- if m.historyNum < len(history)-1 {
- m.historyNum++
- m.response = history[m.historyNum]
- m.cursorx = Count(m.response)
- }
- case "main.(*View).CursorLeft":
- if m.cursorx > 0 {
- m.cursorx--
- }
- case "main.(*View).CursorRight":
- if m.cursorx < Count(m.response) {
- m.cursorx++
- }
- case "main.(*View).CursorStart", "main.(*View).StartOfLine":
- m.cursorx = 0
- case "main.(*View).CursorEnd", "main.(*View).EndOfLine":
- m.cursorx = Count(m.response)
- case "main.(*View).Backspace":
- if m.cursorx > 0 {
- m.response = string([]rune(m.response)[:m.cursorx-1]) + string([]rune(m.response)[m.cursorx:])
- m.cursorx--
- }
- case "main.(*View).Paste":
- clip, _ := clipboard.ReadAll("clipboard")
- m.response = Insert(m.response, m.cursorx, clip)
- m.cursorx += Count(clip)
- }
- }
- }
- }
- }
- }
switch e.Key() {
+ case tcell.KeyCtrlA:
+ m.Start()
+ case tcell.KeyCtrlE:
+ m.End()
+ case tcell.KeyUp:
+ m.UpHistory(history)
+ case tcell.KeyDown:
+ m.DownHistory(history)
+ case tcell.KeyLeft:
+ if e.Modifiers() == tcell.ModCtrl {
+ m.Start()
+ } else if e.Modifiers() == tcell.ModAlt || e.Modifiers() == tcell.ModMeta {
+ m.WordLeft()
+ } else {
+ m.CursorLeft()
+ }
+ case tcell.KeyRight:
+ if e.Modifiers() == tcell.ModCtrl {
+ m.End()
+ } else if e.Modifiers() == tcell.ModAlt || e.Modifiers() == tcell.ModMeta {
+ m.WordRight()
+ } else {
+ m.CursorRight()
+ }
+ case tcell.KeyBackspace2, tcell.KeyBackspace:
+ if e.Modifiers() == tcell.ModCtrl || e.Modifiers() == tcell.ModAlt || e.Modifiers() == tcell.ModMeta {
+ m.DeleteWordLeft()
+ } else {
+ m.Backspace()
+ }
+ case tcell.KeyCtrlW:
+ m.DeleteWordLeft()
+ case tcell.KeyCtrlV:
+ m.Paste()
+ case tcell.KeyCtrlF:
+ m.WordRight()
+ case tcell.KeyCtrlB:
+ m.WordLeft()
case tcell.KeyRune:
m.response = Insert(m.response, m.cursorx, string(e.Rune()))
m.cursorx++
func (m *Messenger) LoadHistory() {
if GetGlobalOption("savehistory").(bool) {
file, err := os.Open(configDir + "/buffers/history")
+ defer file.Close()
var decodedMap map[string][]string
if err == nil {
decoder := gob.NewDecoder(file)
err = decoder.Decode(&decodedMap)
- file.Close()
+
+ if err != nil {
+ m.Error("Error loading history:", err)
+ return
+ }
}
- if err != nil {
- m.Error("Error loading history:", err)
- SetOption("savehistory", "false")
+ if decodedMap != nil {
+ m.history = decodedMap
+ } else {
m.history = make(map[string][]string)
- return
}
-
- m.history = decodedMap
} else {
m.history = make(map[string][]string)
}
// Don't save history past 100
for k, v := range m.history {
if len(v) > 100 {
- m.history[k] = v[0:100]
+ m.history[k] = v[len(m.history[k])-100:]
}
}
file, err := os.Create(configDir + "/buffers/history")
+ defer file.Close()
if err == nil {
encoder := gob.NewEncoder(file)
m.Error("Error saving history:", err)
return
}
- file.Close()
}
}
}