summaryrefslogtreecommitdiffstats
path: root/prompt.go
blob: 27e472b11c90cfcc97af63b3c2fd4f3d3fd09af0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
package main

import (
	"errors"
	"fmt"
	"strings"

	"github.com/jroimartin/gocui"
	"github.com/mkchoi212/fac/binding"
	"github.com/mkchoi212/fac/color"
	"github.com/mkchoi212/fac/conflict"
)

// ErrUnknownCmd is returned when user inputs an invalid character
var ErrUnknownCmd = errors.New("This person doesn't know whats going on")

// ErrOpenEditor is returned when the user wants to open an editor
// Note that the current instance of gocui must be destroyed before opening an editor
var ErrOpenEditor = errors.New("Screen is tainted after opening vim")

// PrintPrompt prints the promptString on the bottom left corner of the screen
// Note that the prompt is composed of two separate views,
// one that displays just the promptString, and another that takes input from the user
func PrintPrompt(g *gocui.Gui) {
	promptString := keyBinding.Summary()

	g.Update(func(g *gocui.Gui) error {
		v, err := g.View(Prompt)
		if err != nil {
			return err
		}
		v.Clear()
		v.MoveCursor(0, 0, true)

		if consecutiveErrCnt == 0 {
			fmt.Fprintf(v, color.Green(color.Regular, promptString))
		} else {
			fmt.Fprintf(v, color.Red(color.Regular, promptString))
		}
		return nil
	})
}

// Evaluate evalutes the user's input character by character
// It returns `ErrUnknownCmd` if the string contains an invalid command
// It also returns `ErrNeedRefresh` if user uses `e` command to open vim
func Evaluate(g *gocui.Gui, v *gocui.View, conf *conflict.Conflict, input string) (err error) {
	for _, c := range input {
		switch string(c) {
		case keyBinding[binding.ScrollUp]:
			Scroll(g, conflicts[cur], Up)
		case keyBinding[binding.ScrollDown]:
			Scroll(g, conflicts[cur], Down)
		case keyBinding[binding.ShowLinesUp]:
			conflicts[cur].TopPeek++
			Select(g, conflicts[cur], false)
		case keyBinding[binding.ShowLinesDown]:
			conflicts[cur].BottomPeek++
			Select(g, conflicts[cur], false)
		case keyBinding[binding.SelectLocal]:
			Resolve(g, v, conflicts[cur], conflict.Local)
		case keyBinding[binding.SelectIncoming]:
			Resolve(g, v, conflicts[cur], conflict.Incoming)
		case keyBinding[binding.NextConflict]:
			Move(g, v, Down)
		case keyBinding[binding.PreviousConflict]:
			Move(g, v, Up)
		case keyBinding[binding.ToggleViewOrientation]:
			viewOrientation = ^viewOrientation
			layout(g)
		case keyBinding[binding.EditCode]:
			globalQuit(g, ErrOpenEditor)
		case keyBinding[binding.ShowHelp], "?":
			Select(g, conflicts[cur], true)
		case keyBinding[binding.QuitApplication]:
			globalQuit(g, gocui.ErrQuit)
		default:
			return ErrUnknownCmd
		}
	}
	return
}

// ParseInput is invoked when the user presses "Enter"
// It `evaluate`s the user's query and reflects the state on the UI
func ParseInput(g *gocui.Gui, v *gocui.View) error {
	in := strings.TrimSuffix(v.Buffer(), "\n")

	if err := Evaluate(g, v, conflicts[cur], in); err != nil {
		if err == ErrUnknownCmd {
			consecutiveErrCnt++
			if consecutiveErrCnt > 3 {
				Select(g, conflicts[cur], true)
			}
		} else {
			return err
		}
	} else {
		consecutiveErrCnt = 0
	}

	PrintPrompt(g)
	return nil
}

// PromptEditor handles user's interaction with the prompt
// Note that user's `ContinuousEvaluation` setting value changes its behavior
func PromptEditor(v *gocui.View, key gocui.Key, ch rune, mod gocui.Modifier) {
	if ch != 0 && mod == 0 {
		if keyBinding[binding.ContinuousEvaluation] == "true" {
			v.Clear()
			v.EditWrite(ch)
			ParseInput(g, v)
			v.SetCursor(0, 0)
		} else {
			v.EditWrite(ch)
		}
		return
	}

	switch key {
	case gocui.KeyEnter:
		ParseInput(g, v)
		v.Clear()
		v.SetCursor(0, 0)
	case gocui.KeySpace:
		v.EditWrite(' ')
	case gocui.KeyBackspace, gocui.KeyBackspace2:
		v.EditDelete(true)
	case gocui.KeyDelete:
		v.EditDelete(false)
	case gocui.KeyInsert:
		v.Overwrite = !v.Overwrite
	case gocui.KeyArrowDown:
		v.SetCursor(len(v.Buffer())-1, 0)
	case gocui.KeyArrowUp:
		v.MoveCursor(0, -1, false)
	case gocui.KeyArrowLeft:
		v.MoveCursor(-1, 0, false)
	case gocui.KeyArrowRight:
		v.MoveCursor(1, 0, false)
	}
}