Skip to content

Commit

Permalink
Autocomplete request headers
Browse files Browse the repository at this point in the history
  • Loading branch information
Benaiah authored and asciimoo committed Mar 3, 2017
1 parent efc1a4b commit ec9e472
Show file tree
Hide file tree
Showing 2 changed files with 191 additions and 1 deletion.
37 changes: 37 additions & 0 deletions request-headers.go
@@ -0,0 +1,37 @@
package main

var REQUEST_HEADERS = []string{
"Accept",
"Accept-Charset",
"Accept-Encoding",
"Accept-Language",
"Accept-Datetime",
"Authorization",
"Cache-Control",
"Connection",
"Cookie",
"Content-Length",
"Content-MD5",
"Content-Type",
"Date",
"Expect",
"Forwarded",
"From",
"Host",
"If-Match",
"If-Modified-Since",
"If-None-Match",
"If-Range",
"If-Unmodified-Since",
"Max-Forwards",
"Origin",
"Pragma",
"Proxy-Authorization",
"Range",
"Referer",
"TE",
"User-Agent",
"Upgrade",
"Via",
"Warning",
}
155 changes: 154 additions & 1 deletion wuzz.go
Expand Up @@ -48,6 +48,7 @@ const (

SEARCH_PROMPT_VIEW = "prompt"
POPUP_VIEW = "popup_view"
AUTOCOMPLETE_VIEW = "autocomplete_view"
ERROR_VIEW = "error_view"
HISTORY_VIEW = "history"
SAVE_DIALOG_VIEW = "save-dialog"
Expand Down Expand Up @@ -131,6 +132,11 @@ var VIEW_POSITIONS = map[string]viewPosition{
position{0.5, -1},
position{0.5, -9999}, // set before usage using len(msg)
position{0.5, 1}},
AUTOCOMPLETE_VIEW: {
position{0, -9999},
position{0, -9999},
position{0, -9999},
position{0, -9999}},
}

type viewProperties struct {
Expand Down Expand Up @@ -177,7 +183,9 @@ var VIEW_PROPERTIES = map[string]viewProperties{
frame: true,
editable: true,
wrap: false,
editor: &defaultEditor,
editor: &AutocompleteEditor{&defaultEditor, func(str string) []string {
return completeFromSlice(str, REQUEST_HEADERS)
}, []string{}, false},
},
RESPONSE_HEADERS_VIEW: {
title: "Response headers",
Expand Down Expand Up @@ -215,6 +223,13 @@ var VIEW_PROPERTIES = map[string]viewProperties{
wrap: false,
editor: nil,
},
AUTOCOMPLETE_VIEW: {
title: "",
frame: false,
editable: false,
wrap: false,
editor: nil,
},
}

var METHODS = []string{
Expand Down Expand Up @@ -289,6 +304,13 @@ type ViewEditor struct {
origEditor gocui.Editor
}

type AutocompleteEditor struct {
wuzzEditor *ViewEditor
completions func(string) []string
currentCompletions []string
isAutocompleting bool
}

type SearchEditor struct {
wuzzEditor *ViewEditor
}
Expand Down Expand Up @@ -333,6 +355,88 @@ func (e *ViewEditor) Edit(v *gocui.View, key gocui.Key, ch rune, mod gocui.Modif
e.origEditor.Edit(v, key, ch, mod)
}

var symbolPattern = regexp.MustCompile("[a-zA-Z0-9-]+$")

func getLastSymbol(str string) string {
return symbolPattern.FindString(str)
}

func completeFromSlice(str string, completions []string) []string {
completed := []string{}
if str == "" || strings.TrimRight(str, " \n") != str {
return completed
}
for _, completion := range completions {
if strings.HasPrefix(completion, str) && str != completion {
completed = append(completed, completion)
}
}
return completed
}

func (e *AutocompleteEditor) Edit(v *gocui.View, key gocui.Key, ch rune, mod gocui.Modifier) {
if key != gocui.KeyEnter {
e.wuzzEditor.Edit(v, key, ch, mod)
}

cx, cy := v.Cursor()
line, err := v.Line(cy)
trimmedLine := line[:cx]

if err != nil {
e.wuzzEditor.Edit(v, key, ch, mod)
return
}

lastSymbol := getLastSymbol(trimmedLine)
if key == gocui.KeyEnter && e.isAutocompleting {
currentCompletion := e.currentCompletions[0]
shouldDelete := true
if len(e.currentCompletions) == 1 {
shouldDelete = false
}

if shouldDelete {
for _ = range lastSymbol {
v.EditDelete(true)
}
}
for _, char := range currentCompletion {
v.EditWrite(char)
}
closeAutocomplete(e.wuzzEditor.g)
e.isAutocompleting = false
return
} else if key == gocui.KeyEnter {
e.wuzzEditor.Edit(v, key, ch, mod)
}

closeAutocomplete(e.wuzzEditor.g)
e.isAutocompleting = false

completions := e.completions(lastSymbol)
e.currentCompletions = completions

cx, cy = v.Cursor()
maxX, maxY := e.wuzzEditor.g.Size()
sx, _ := v.Size()
pos := VIEW_POSITIONS[v.Name()]
ox := pos.x0.getCoordinate(maxX)
oy := pos.y0.getCoordinate(maxY)

maxWidth := sx - cx
maxHeight := 10

if len(completions) > 0 {
comps := completions
if len(comps) == 1 {
comps[0] = comps[0][len(lastSymbol):]
}
showAutocomplete(comps, ox+cx, oy+cy, maxWidth, maxHeight, e.wuzzEditor.g)
e.isAutocompleting = true
}
}

func (e *SearchEditor) Edit(v *gocui.View, key gocui.Key, ch rune, mod gocui.Modifier) {
e.wuzzEditor.Edit(v, key, ch, mod)
e.wuzzEditor.g.Execute(func(g *gocui.Gui) error {
Expand Down Expand Up @@ -508,6 +612,55 @@ func popup(g *gocui.Gui, msg string) {
}
}

func minInt(x, y int) int {
if x < y {
return x
}
return y
}

func closeAutocomplete(g *gocui.Gui) {
g.DeleteView(AUTOCOMPLETE_VIEW)
}

func showAutocomplete(completions []string, left, top, maxWidth, maxHeight int, g *gocui.Gui) {
// Get the width of the widest completion
completionsWidth := 0
for _, completion := range completions {
thisCompletionWidth := len(completion)
if thisCompletionWidth > completionsWidth {
completionsWidth = thisCompletionWidth
}
}

// Get the width and height of the autocomplete window
width := minInt(completionsWidth, maxWidth)
height := minInt(len(completions), maxHeight)

newPos := viewPosition{
x0: position{0, left},
y0: position{0, top},
x1: position{0, left + width + 1},
y1: position{0, top + height + 1},
}

VIEW_POSITIONS[AUTOCOMPLETE_VIEW] = newPos

p := VIEW_PROPERTIES[AUTOCOMPLETE_VIEW]
p.text = strings.Join(append(completions, fmt.Sprint(maxHeight)+"x"+fmt.Sprint(maxWidth)), "\n")
VIEW_PROPERTIES[AUTOCOMPLETE_VIEW] = p

if v, err := setView(g, AUTOCOMPLETE_VIEW); err != nil {
if err != gocui.ErrUnknownView {
return
}
setViewProperties(v, AUTOCOMPLETE_VIEW)
v.BgColor = gocui.ColorRed
v.FgColor = gocui.ColorDefault
g.SetViewOnTop(AUTOCOMPLETE_VIEW)
}
}

func (a *App) SubmitRequest(g *gocui.Gui, _ *gocui.View) error {
vrb, _ := g.View(RESPONSE_BODY_VIEW)
vrb.Clear()
Expand Down

0 comments on commit ec9e472

Please sign in to comment.