From f39864cbfee76fb5d365cb581bba40e5f31c00c6 Mon Sep 17 00:00:00 2001
From: Pawel Wolowiec
Date: Fri, 17 Feb 2017 00:22:58 +0100
Subject: [PATCH 01/15] Moved most view properties to the top, leaving Layout
function much smaller
---
wuzz.go | 247 ++++++++++++++++++++++++++++++--------------------------
1 file changed, 133 insertions(+), 114 deletions(-)
diff --git a/wuzz.go b/wuzz.go
index 8038ce7..cb3b5bc 100644
--- a/wuzz.go
+++ b/wuzz.go
@@ -31,6 +31,7 @@ const VERSION = "0.1.0"
const TIMEOUT_DURATION = 5 // in seconds
const WINDOWS_OS = "windows"
+const SEARCH_PROMPT = "search> "
const (
ALL_VIEWS = ""
@@ -44,31 +45,23 @@ const (
RESPONSE_HEADERS_VIEW = "response-headers"
RESPONSE_BODY_VIEW = "response-body"
- PROMPT = "prompt"
- POPUP_VIEW = "popup_view"
- ERROR_VIEW = "error_view"
- HISTORY_VIEW = "history"
- SAVE_DIALOG_VIEW = "save-dialog"
- SAVE_RESULT_VIEW = "save-result"
- METHOD_LIST_VIEW = "method-list"
- HELP_VIEW = "help"
+ SEARCH_PROMPT_VIEW = "prompt"
+ POPUP_VIEW = "popup_view"
+ ERROR_VIEW = "error_view"
+ HISTORY_VIEW = "history"
+ SAVE_DIALOG_VIEW = "save-dialog"
+ SAVE_RESULT_VIEW = "save-result"
+ METHOD_LIST_VIEW = "method-list"
+ HELP_VIEW = "help"
)
var VIEW_TITLES = map[string]string{
- URL_VIEW: "URL - press F1 for help",
- URL_PARAMS_VIEW: "URL params",
- REQUEST_METHOD_VIEW: "Method",
- REQUEST_DATA_VIEW: "Request data (POST/PUT)",
- REQUEST_HEADERS_VIEW: "Request headers",
- SEARCH_VIEW: "search> ",
- RESPONSE_HEADERS_VIEW: "Response headers",
- RESPONSE_BODY_VIEW: "Response body",
-
POPUP_VIEW: "Info",
ERROR_VIEW: "Error",
HISTORY_VIEW: "History",
SAVE_DIALOG_VIEW: "Save Response (enter to submit, ctrl+q to cancel)",
METHOD_LIST_VIEW: "Methods",
+ HELP_VIEW: "Help",
}
type position struct {
@@ -127,7 +120,7 @@ var VIEW_POSITIONS = map[string]viewPosition{
position{0.0, 0},
position{1.0, -2},
position{1.0, -2}},
- PROMPT: {
+ SEARCH_PROMPT_VIEW: {
position{0.0, -1},
position{1.0, -3},
position{0.0, 8},
@@ -139,6 +132,80 @@ var VIEW_POSITIONS = map[string]viewPosition{
position{0.5, 1}},
}
+type viewProperties struct {
+ title string
+ frame bool
+ editable bool
+ wrap bool
+ editor gocui.Editor
+}
+
+var VIEW_PROPERTIES = map[string]viewProperties{
+ URL_VIEW: {
+ title: "URL - press F1 for help",
+ frame: true,
+ editable: true,
+ wrap: true,
+ editor: &singleLineEditor{&defaultEditor},
+ },
+ URL_PARAMS_VIEW: {
+ title: "URL params",
+ frame: true,
+ editable: true,
+ wrap: true,
+ editor: &defaultEditor,
+ },
+ REQUEST_METHOD_VIEW: {
+ title: "Method",
+ frame: true,
+ editable: true,
+ wrap: true,
+ editor: &singleLineEditor{&defaultEditor},
+ },
+ REQUEST_DATA_VIEW: {
+ title: "Request data (POST/PUT)",
+ frame: true,
+ editable: true,
+ wrap: true,
+ editor: &defaultEditor,
+ },
+ REQUEST_HEADERS_VIEW: {
+ title: "Request headers",
+ frame: true,
+ editable: true,
+ wrap: false,
+ editor: &defaultEditor,
+ },
+ RESPONSE_HEADERS_VIEW: {
+ title: "Response headers",
+ frame: true,
+ editable: true,
+ wrap: true,
+ editor: nil, // should be set using a.getViewEditor(g)
+ },
+ RESPONSE_BODY_VIEW: {
+ title: "Response body",
+ frame: true,
+ editable: true,
+ wrap: true,
+ editor: nil, // should be set using a.getViewEditor(g)
+ },
+ SEARCH_VIEW: {
+ title: "",
+ frame: false,
+ editable: true,
+ wrap: true,
+ editor: &singleLineEditor{&SearchEditor{&defaultEditor}},
+ },
+ SEARCH_PROMPT_VIEW: {
+ title: "",
+ frame: false,
+ editable: false,
+ wrap: true,
+ editor: nil,
+ },
+}
+
var METHODS []string = []string{
http.MethodGet,
http.MethodPost,
@@ -278,26 +345,31 @@ func (e singleLineEditor) Edit(v *gocui.View, key gocui.Key, ch rune, mod gocui.
//
+func (a *App) getResponseViewEditor(g *gocui.Gui) gocui.Editor {
+ return &ViewEditor{a, g, false, gocui.EditorFunc(func(v *gocui.View, key gocui.Key, ch rune, mod gocui.Modifier) {
+ return
+ })}
+}
+
func (p position) getCoordinate(max int) int {
return int(p.pct*float32(max)) + p.abs
}
-func setView(g *gocui.Gui, maxX, maxY int, viewName string) (*gocui.View, error) {
+func setView(g *gocui.Gui, viewName string) (*gocui.View, error) {
+ maxX, maxY := g.Size()
position := VIEW_POSITIONS[viewName]
return g.SetView(viewName,
- position.x0.getCoordinate(maxX),
- position.y0.getCoordinate(maxY),
- position.x1.getCoordinate(maxX),
- position.y1.getCoordinate(maxY))
+ position.x0.getCoordinate(maxX+1),
+ position.y0.getCoordinate(maxY+1),
+ position.x1.getCoordinate(maxX+1),
+ position.y1.getCoordinate(maxY+1))
}
func (a *App) Layout(g *gocui.Gui) error {
maxX, maxY := g.Size()
- maxX++
- maxY++
- if maxX-1 < MIN_WIDTH || maxY-1 < MIN_HEIGHT {
- if v, err := setView(g, maxX, maxY, ERROR_VIEW); err != nil {
+ if maxX < MIN_WIDTH || maxY < MIN_HEIGHT {
+ if v, err := setView(g, ERROR_VIEW); err != nil {
if err != gocui.ErrUnknownView {
return err
}
@@ -314,95 +386,45 @@ func (a *App) Layout(g *gocui.Gui) error {
a.setView(g)
}
- if v, err := setView(g, maxX, maxY, URL_VIEW); err != nil {
- if err != gocui.ErrUnknownView {
- return err
- }
- setViewDefaults(v)
- v.Title = VIEW_TITLES[URL_VIEW]
- v.Editable = true
- v.Overwrite = false
- v.Editor = &singleLineEditor{&defaultEditor}
- setViewTextAndCursor(v, a.config.General.DefaultURLScheme+"://")
+ for _, name := range []string{RESPONSE_HEADERS_VIEW, RESPONSE_BODY_VIEW} {
+ vp := VIEW_PROPERTIES[name]
+ vp.editor = a.getResponseViewEditor(g)
+ VIEW_PROPERTIES[name] = vp
}
- if v, err := setView(g, maxX, maxY, URL_PARAMS_VIEW); err != nil {
- if err != gocui.ErrUnknownView {
- return err
- }
- setViewDefaults(v)
- v.Editable = true
- v.Title = VIEW_TITLES[URL_PARAMS_VIEW]
- v.Editor = &defaultEditor
- }
- if v, err := setView(g, maxX, maxY, REQUEST_METHOD_VIEW); err != nil {
- if err != gocui.ErrUnknownView {
- return err
- }
- setViewDefaults(v)
- v.Editable = true
- v.Title = VIEW_TITLES[REQUEST_METHOD_VIEW]
- v.Editor = &singleLineEditor{&defaultEditor}
- setViewTextAndCursor(v, DEFAULT_METHOD)
- }
- if v, err := setView(g, maxX, maxY, REQUEST_DATA_VIEW); err != nil {
- if err != gocui.ErrUnknownView {
- return err
- }
- setViewDefaults(v)
- v.Editable = true
- v.Title = VIEW_TITLES[REQUEST_DATA_VIEW]
- v.Editor = &defaultEditor
- }
- if v, err := setView(g, maxX, maxY, REQUEST_HEADERS_VIEW); err != nil {
- if err != gocui.ErrUnknownView {
- return err
- }
- setViewDefaults(v)
- v.Wrap = false
- v.Editable = true
- v.Title = VIEW_TITLES[REQUEST_HEADERS_VIEW]
- v.Editor = &defaultEditor
- }
- if v, err := setView(g, maxX, maxY, RESPONSE_HEADERS_VIEW); err != nil {
- if err != gocui.ErrUnknownView {
- return err
+ for _, name := range []string{
+ URL_VIEW,
+ URL_PARAMS_VIEW,
+ REQUEST_METHOD_VIEW,
+ REQUEST_DATA_VIEW,
+ REQUEST_HEADERS_VIEW,
+ RESPONSE_HEADERS_VIEW,
+ RESPONSE_BODY_VIEW,
+ SEARCH_PROMPT_VIEW,
+ SEARCH_VIEW,
+ } {
+ if v, err := setView(g, name); err != nil {
+ if err != gocui.ErrUnknownView {
+ return err
+ }
+ v.Title = VIEW_PROPERTIES[name].title
+ v.Frame = VIEW_PROPERTIES[name].frame
+ v.Editable = VIEW_PROPERTIES[name].editable
+ v.Wrap = VIEW_PROPERTIES[name].wrap
+ v.Editor = VIEW_PROPERTIES[name].editor
}
- setViewDefaults(v)
- v.Title = VIEW_TITLES[RESPONSE_HEADERS_VIEW]
- v.Editable = true
- v.Editor = &ViewEditor{a, g, false, gocui.EditorFunc(func(v *gocui.View, key gocui.Key, ch rune, mod gocui.Modifier) {
- return
- })}
}
- if v, err := setView(g, maxX, maxY, RESPONSE_BODY_VIEW); err != nil {
- if err != gocui.ErrUnknownView {
- return err
- }
- setViewDefaults(v)
- v.Title = VIEW_TITLES[RESPONSE_BODY_VIEW]
- v.Editable = true
- v.Editor = &ViewEditor{a, g, false, gocui.EditorFunc(func(v *gocui.View, key gocui.Key, ch rune, mod gocui.Modifier) {
- return
- })}
+
+ if v, err := g.View(URL_VIEW); err == nil {
+ setViewTextAndCursor(v, a.config.General.DefaultURLScheme+"://")
}
- if v, err := setView(g, maxX, maxY, PROMPT); err != nil {
- if err != gocui.ErrUnknownView {
- return err
- }
- v.Frame = false
- v.Wrap = true
- setViewTextAndCursor(v, VIEW_TITLES[SEARCH_VIEW])
+ if v, err := g.View(REQUEST_METHOD_VIEW); err == nil {
+ setViewTextAndCursor(v, DEFAULT_METHOD)
}
- if v, err := setView(g, maxX, maxY, SEARCH_VIEW); err != nil {
- if err != gocui.ErrUnknownView {
- return err
- }
- v.Frame = false
- v.Editable = true
- v.Editor = &singleLineEditor{&SearchEditor{&defaultEditor}}
- v.Wrap = true
+ if v, err := g.View(SEARCH_PROMPT_VIEW); err == nil {
+ setViewTextAndCursor(v, SEARCH_PROMPT)
}
+
return nil
}
@@ -435,15 +457,12 @@ func (a *App) setViewByName(g *gocui.Gui, name string) error {
func popup(g *gocui.Gui, msg string) {
var popup *gocui.View
var err error
- maxX, maxY := g.Size()
- maxX++
- maxY++
p := VIEW_POSITIONS[POPUP_VIEW]
p.x0.abs = -len(msg)/2 - 1
p.x1.abs = len(msg)/2 + 1
VIEW_POSITIONS[POPUP_VIEW] = p
- if popup, err = setView(g, maxX, maxY, POPUP_VIEW); err != nil {
+ if popup, err = setView(g, POPUP_VIEW); err != nil {
if err != gocui.ErrUnknownView {
return
}
@@ -756,7 +775,7 @@ func (a *App) SetKeys(g *gocui.Gui) error {
if err != nil {
return err
}
- help.Title = "Help"
+ help.Title = VIEW_TITLES[HELP_VIEW]
help.Highlight = false
fmt.Fprint(help, "Keybindings:\n")
a.printViewKeybindings(help, "global")
From 54ef832dea7be3ae67ab00c734e4a907e515c997 Mon Sep 17 00:00:00 2001
From: Adam Tauber
Date: Fri, 17 Feb 2017 00:29:37 +0100
Subject: [PATCH 02/15] [fix] disable wrapping of editable views - related to
#61
---
wuzz.go | 248 ++++++++++++++++++++++++++------------------------------
1 file changed, 114 insertions(+), 134 deletions(-)
diff --git a/wuzz.go b/wuzz.go
index 6bacee0..19f0171 100644
--- a/wuzz.go
+++ b/wuzz.go
@@ -32,7 +32,6 @@ const VERSION = "0.1.0"
const TIMEOUT_DURATION = 5 // in seconds
const WINDOWS_OS = "windows"
-const SEARCH_PROMPT = "search> "
const (
ALL_VIEWS = ""
@@ -46,23 +45,31 @@ const (
RESPONSE_HEADERS_VIEW = "response-headers"
RESPONSE_BODY_VIEW = "response-body"
- SEARCH_PROMPT_VIEW = "prompt"
- POPUP_VIEW = "popup_view"
- ERROR_VIEW = "error_view"
- HISTORY_VIEW = "history"
- SAVE_DIALOG_VIEW = "save-dialog"
- SAVE_RESULT_VIEW = "save-result"
- METHOD_LIST_VIEW = "method-list"
- HELP_VIEW = "help"
+ PROMPT = "prompt"
+ POPUP_VIEW = "popup_view"
+ ERROR_VIEW = "error_view"
+ HISTORY_VIEW = "history"
+ SAVE_DIALOG_VIEW = "save-dialog"
+ SAVE_RESULT_VIEW = "save-result"
+ METHOD_LIST_VIEW = "method-list"
+ HELP_VIEW = "help"
)
var VIEW_TITLES = map[string]string{
+ URL_VIEW: "URL - press F1 for help",
+ URL_PARAMS_VIEW: "URL params",
+ REQUEST_METHOD_VIEW: "Method",
+ REQUEST_DATA_VIEW: "Request data (POST/PUT/PATCH)",
+ REQUEST_HEADERS_VIEW: "Request headers",
+ SEARCH_VIEW: "search> ",
+ RESPONSE_HEADERS_VIEW: "Response headers",
+ RESPONSE_BODY_VIEW: "Response body",
+
POPUP_VIEW: "Info",
ERROR_VIEW: "Error",
HISTORY_VIEW: "History",
SAVE_DIALOG_VIEW: "Save Response (enter to submit, ctrl+q to cancel)",
METHOD_LIST_VIEW: "Methods",
- HELP_VIEW: "Help",
}
type position struct {
@@ -121,7 +128,7 @@ var VIEW_POSITIONS = map[string]viewPosition{
position{0.0, 0},
position{1.0, -2},
position{1.0, -2}},
- SEARCH_PROMPT_VIEW: {
+ PROMPT: {
position{0.0, -1},
position{1.0, -3},
position{0.0, 8},
@@ -133,80 +140,6 @@ var VIEW_POSITIONS = map[string]viewPosition{
position{0.5, 1}},
}
-type viewProperties struct {
- title string
- frame bool
- editable bool
- wrap bool
- editor gocui.Editor
-}
-
-var VIEW_PROPERTIES = map[string]viewProperties{
- URL_VIEW: {
- title: "URL - press F1 for help",
- frame: true,
- editable: true,
- wrap: true,
- editor: &singleLineEditor{&defaultEditor},
- },
- URL_PARAMS_VIEW: {
- title: "URL params",
- frame: true,
- editable: true,
- wrap: true,
- editor: &defaultEditor,
- },
- REQUEST_METHOD_VIEW: {
- title: "Method",
- frame: true,
- editable: true,
- wrap: true,
- editor: &singleLineEditor{&defaultEditor},
- },
- REQUEST_DATA_VIEW: {
- title: "Request data (POST/PUT/PATCH)",
- frame: true,
- editable: true,
- wrap: true,
- editor: &defaultEditor,
- },
- REQUEST_HEADERS_VIEW: {
- title: "Request headers",
- frame: true,
- editable: true,
- wrap: false,
- editor: &defaultEditor,
- },
- RESPONSE_HEADERS_VIEW: {
- title: "Response headers",
- frame: true,
- editable: true,
- wrap: true,
- editor: nil, // should be set using a.getViewEditor(g)
- },
- RESPONSE_BODY_VIEW: {
- title: "Response body",
- frame: true,
- editable: true,
- wrap: true,
- editor: nil, // should be set using a.getViewEditor(g)
- },
- SEARCH_VIEW: {
- title: "",
- frame: false,
- editable: true,
- wrap: true,
- editor: &singleLineEditor{&SearchEditor{&defaultEditor}},
- },
- SEARCH_PROMPT_VIEW: {
- title: "",
- frame: false,
- editable: false,
- wrap: true,
- editor: nil,
- },
-}
-
var METHODS []string = []string{
http.MethodGet,
http.MethodPost,
@@ -346,31 +279,26 @@ func (e singleLineEditor) Edit(v *gocui.View, key gocui.Key, ch rune, mod gocui.
//
-func (a *App) getResponseViewEditor(g *gocui.Gui) gocui.Editor {
- return &ViewEditor{a, g, false, gocui.EditorFunc(func(v *gocui.View, key gocui.Key, ch rune, mod gocui.Modifier) {
- return
- })}
-}
-
func (p position) getCoordinate(max int) int {
return int(p.pct*float32(max)) + p.abs
}
-func setView(g *gocui.Gui, viewName string) (*gocui.View, error) {
- maxX, maxY := g.Size()
+func setView(g *gocui.Gui, maxX, maxY int, viewName string) (*gocui.View, error) {
position := VIEW_POSITIONS[viewName]
return g.SetView(viewName,
- position.x0.getCoordinate(maxX+1),
- position.y0.getCoordinate(maxY+1),
- position.x1.getCoordinate(maxX+1),
- position.y1.getCoordinate(maxY+1))
+ position.x0.getCoordinate(maxX),
+ position.y0.getCoordinate(maxY),
+ position.x1.getCoordinate(maxX),
+ position.y1.getCoordinate(maxY))
}
func (a *App) Layout(g *gocui.Gui) error {
maxX, maxY := g.Size()
+ maxX++
+ maxY++
- if maxX < MIN_WIDTH || maxY < MIN_HEIGHT {
- if v, err := setView(g, ERROR_VIEW); err != nil {
+ if maxX-1 < MIN_WIDTH || maxY-1 < MIN_HEIGHT {
+ if v, err := setView(g, maxX, maxY, ERROR_VIEW); err != nil {
if err != gocui.ErrUnknownView {
return err
}
@@ -387,45 +315,94 @@ func (a *App) Layout(g *gocui.Gui) error {
a.setView(g)
}
- for _, name := range []string{RESPONSE_HEADERS_VIEW, RESPONSE_BODY_VIEW} {
- vp := VIEW_PROPERTIES[name]
- vp.editor = a.getResponseViewEditor(g)
- VIEW_PROPERTIES[name] = vp
+ if v, err := setView(g, maxX, maxY, URL_VIEW); err != nil {
+ if err != gocui.ErrUnknownView {
+ return err
+ }
+ setViewDefaults(v)
+ v.Title = VIEW_TITLES[URL_VIEW]
+ v.Editable = true
+ v.Overwrite = false
+ v.Editor = &singleLineEditor{&defaultEditor}
+ setViewTextAndCursor(v, a.config.General.DefaultURLScheme+"://")
}
-
- for _, name := range []string{
- URL_VIEW,
- URL_PARAMS_VIEW,
- REQUEST_METHOD_VIEW,
- REQUEST_DATA_VIEW,
- REQUEST_HEADERS_VIEW,
- RESPONSE_HEADERS_VIEW,
- RESPONSE_BODY_VIEW,
- SEARCH_PROMPT_VIEW,
- SEARCH_VIEW,
- } {
- if v, err := setView(g, name); err != nil {
- if err != gocui.ErrUnknownView {
- return err
- }
- v.Title = VIEW_PROPERTIES[name].title
- v.Frame = VIEW_PROPERTIES[name].frame
- v.Editable = VIEW_PROPERTIES[name].editable
- v.Wrap = VIEW_PROPERTIES[name].wrap
- v.Editor = VIEW_PROPERTIES[name].editor
+ if v, err := setView(g, maxX, maxY, URL_PARAMS_VIEW); err != nil {
+ if err != gocui.ErrUnknownView {
+ return err
}
+ setViewDefaults(v)
+ v.Editable = true
+ v.Title = VIEW_TITLES[URL_PARAMS_VIEW]
+ v.Editor = &defaultEditor
}
+ if v, err := setView(g, maxX, maxY, REQUEST_METHOD_VIEW); err != nil {
+ if err != gocui.ErrUnknownView {
+ return err
+ }
+ setViewDefaults(v)
+ v.Editable = true
+ v.Title = VIEW_TITLES[REQUEST_METHOD_VIEW]
+ v.Editor = &singleLineEditor{&defaultEditor}
- if v, err := g.View(URL_VIEW); err == nil {
- setViewTextAndCursor(v, a.config.General.DefaultURLScheme+"://")
- }
- if v, err := g.View(REQUEST_METHOD_VIEW); err == nil {
setViewTextAndCursor(v, DEFAULT_METHOD)
}
- if v, err := g.View(SEARCH_PROMPT_VIEW); err == nil {
- setViewTextAndCursor(v, SEARCH_PROMPT)
+ if v, err := setView(g, maxX, maxY, REQUEST_DATA_VIEW); err != nil {
+ if err != gocui.ErrUnknownView {
+ return err
+ }
+ setViewDefaults(v)
+ v.Editable = true
+ v.Title = VIEW_TITLES[REQUEST_DATA_VIEW]
+ v.Editor = &defaultEditor
+ }
+ if v, err := setView(g, maxX, maxY, REQUEST_HEADERS_VIEW); err != nil {
+ if err != gocui.ErrUnknownView {
+ return err
+ }
+ setViewDefaults(v)
+ v.Editable = true
+ v.Title = VIEW_TITLES[REQUEST_HEADERS_VIEW]
+ v.Editor = &defaultEditor
+ }
+ if v, err := setView(g, maxX, maxY, RESPONSE_HEADERS_VIEW); err != nil {
+ if err != gocui.ErrUnknownView {
+ return err
+ }
+ setViewDefaults(v)
+ v.Wrap = true
+ v.Title = VIEW_TITLES[RESPONSE_HEADERS_VIEW]
+ v.Editable = true
+ v.Editor = &ViewEditor{a, g, false, gocui.EditorFunc(func(v *gocui.View, key gocui.Key, ch rune, mod gocui.Modifier) {
+ return
+ })}
+ }
+ if v, err := setView(g, maxX, maxY, RESPONSE_BODY_VIEW); err != nil {
+ if err != gocui.ErrUnknownView {
+ return err
+ }
+ setViewDefaults(v)
+ v.Wrap = true
+ v.Title = VIEW_TITLES[RESPONSE_BODY_VIEW]
+ v.Editable = true
+ v.Editor = &ViewEditor{a, g, false, gocui.EditorFunc(func(v *gocui.View, key gocui.Key, ch rune, mod gocui.Modifier) {
+ return
+ })}
+ }
+ if v, err := setView(g, maxX, maxY, PROMPT); err != nil {
+ if err != gocui.ErrUnknownView {
+ return err
+ }
+ v.Frame = false
+ setViewTextAndCursor(v, VIEW_TITLES[SEARCH_VIEW])
+ }
+ if v, err := setView(g, maxX, maxY, SEARCH_VIEW); err != nil {
+ if err != gocui.ErrUnknownView {
+ return err
+ }
+ v.Frame = false
+ v.Editable = true
+ v.Editor = &singleLineEditor{&SearchEditor{&defaultEditor}}
}
-
return nil
}
@@ -458,12 +435,15 @@ func (a *App) setViewByName(g *gocui.Gui, name string) error {
func popup(g *gocui.Gui, msg string) {
var popup *gocui.View
var err error
+ maxX, maxY := g.Size()
+ maxX++
+ maxY++
p := VIEW_POSITIONS[POPUP_VIEW]
p.x0.abs = -len(msg)/2 - 1
p.x1.abs = len(msg)/2 + 1
VIEW_POSITIONS[POPUP_VIEW] = p
- if popup, err = setView(g, POPUP_VIEW); err != nil {
+ if popup, err = setView(g, maxX, maxY, POPUP_VIEW); err != nil {
if err != gocui.ErrUnknownView {
return
}
@@ -781,7 +761,7 @@ func (a *App) SetKeys(g *gocui.Gui) error {
if err != nil {
return err
}
- help.Title = VIEW_TITLES[HELP_VIEW]
+ help.Title = "Help"
help.Highlight = false
fmt.Fprint(help, "Keybindings:\n")
a.printViewKeybindings(help, "global")
@@ -1219,7 +1199,7 @@ func getViewValue(g *gocui.Gui, name string) string {
func setViewDefaults(v *gocui.View) {
v.Frame = true
- v.Wrap = true
+ v.Wrap = false
}
func setViewTextAndCursor(v *gocui.View, s string) {
From f131e1ad5ab78305d57e76601843efefd3a4339e Mon Sep 17 00:00:00 2001
From: Pawel Wolowiec
Date: Fri, 17 Feb 2017 00:45:16 +0100
Subject: [PATCH 03/15] Moved most view properties to the top, leaving Layout
function much smaller
2nd commit due to master changes
---
wuzz.go | 248 ++++++++++++++++++++++++++++++--------------------------
1 file changed, 134 insertions(+), 114 deletions(-)
diff --git a/wuzz.go b/wuzz.go
index 19f0171..c64d947 100644
--- a/wuzz.go
+++ b/wuzz.go
@@ -32,6 +32,7 @@ const VERSION = "0.1.0"
const TIMEOUT_DURATION = 5 // in seconds
const WINDOWS_OS = "windows"
+const SEARCH_PROMPT = "search> "
const (
ALL_VIEWS = ""
@@ -45,31 +46,23 @@ const (
RESPONSE_HEADERS_VIEW = "response-headers"
RESPONSE_BODY_VIEW = "response-body"
- PROMPT = "prompt"
- POPUP_VIEW = "popup_view"
- ERROR_VIEW = "error_view"
- HISTORY_VIEW = "history"
- SAVE_DIALOG_VIEW = "save-dialog"
- SAVE_RESULT_VIEW = "save-result"
- METHOD_LIST_VIEW = "method-list"
- HELP_VIEW = "help"
+ SEARCH_PROMPT_VIEW = "prompt"
+ POPUP_VIEW = "popup_view"
+ ERROR_VIEW = "error_view"
+ HISTORY_VIEW = "history"
+ SAVE_DIALOG_VIEW = "save-dialog"
+ SAVE_RESULT_VIEW = "save-result"
+ METHOD_LIST_VIEW = "method-list"
+ HELP_VIEW = "help"
)
var VIEW_TITLES = map[string]string{
- URL_VIEW: "URL - press F1 for help",
- URL_PARAMS_VIEW: "URL params",
- REQUEST_METHOD_VIEW: "Method",
- REQUEST_DATA_VIEW: "Request data (POST/PUT/PATCH)",
- REQUEST_HEADERS_VIEW: "Request headers",
- SEARCH_VIEW: "search> ",
- RESPONSE_HEADERS_VIEW: "Response headers",
- RESPONSE_BODY_VIEW: "Response body",
-
POPUP_VIEW: "Info",
ERROR_VIEW: "Error",
HISTORY_VIEW: "History",
SAVE_DIALOG_VIEW: "Save Response (enter to submit, ctrl+q to cancel)",
METHOD_LIST_VIEW: "Methods",
+ HELP_VIEW: "Help",
}
type position struct {
@@ -128,7 +121,7 @@ var VIEW_POSITIONS = map[string]viewPosition{
position{0.0, 0},
position{1.0, -2},
position{1.0, -2}},
- PROMPT: {
+ SEARCH_PROMPT_VIEW: {
position{0.0, -1},
position{1.0, -3},
position{0.0, 8},
@@ -140,6 +133,80 @@ var VIEW_POSITIONS = map[string]viewPosition{
position{0.5, 1}},
}
+type viewProperties struct {
+ title string
+ frame bool
+ editable bool
+ wrap bool
+ editor gocui.Editor
+}
+
+var VIEW_PROPERTIES = map[string]viewProperties{
+ URL_VIEW: {
+ title: "URL - press F1 for help",
+ frame: true,
+ editable: true,
+ wrap: false,
+ editor: &singleLineEditor{&defaultEditor},
+ },
+ URL_PARAMS_VIEW: {
+ title: "URL params",
+ frame: true,
+ editable: true,
+ wrap: false,
+ editor: &defaultEditor,
+ },
+ REQUEST_METHOD_VIEW: {
+ title: "Method",
+ frame: true,
+ editable: true,
+ wrap: false,
+ editor: &singleLineEditor{&defaultEditor},
+ },
+ REQUEST_DATA_VIEW: {
+ title: "Request data (POST/PUT/PATCH)",
+ frame: true,
+ editable: true,
+ wrap: false,
+ editor: &defaultEditor,
+ },
+ REQUEST_HEADERS_VIEW: {
+ title: "Request headers",
+ frame: true,
+ editable: true,
+ wrap: false,
+ editor: &defaultEditor,
+ },
+ RESPONSE_HEADERS_VIEW: {
+ title: "Response headers",
+ frame: true,
+ editable: true,
+ wrap: true,
+ editor: nil, // should be set using a.getViewEditor(g)
+ },
+ RESPONSE_BODY_VIEW: {
+ title: "Response body",
+ frame: true,
+ editable: true,
+ wrap: true,
+ editor: nil, // should be set using a.getViewEditor(g)
+ },
+ SEARCH_VIEW: {
+ title: "",
+ frame: false,
+ editable: true,
+ wrap: false,
+ editor: &singleLineEditor{&SearchEditor{&defaultEditor}},
+ },
+ SEARCH_PROMPT_VIEW: {
+ title: "",
+ frame: false,
+ editable: false,
+ wrap: false,
+ editor: nil,
+ },
+}
+
var METHODS []string = []string{
http.MethodGet,
http.MethodPost,
@@ -279,26 +346,31 @@ func (e singleLineEditor) Edit(v *gocui.View, key gocui.Key, ch rune, mod gocui.
//
+func (a *App) getResponseViewEditor(g *gocui.Gui) gocui.Editor {
+ return &ViewEditor{a, g, false, gocui.EditorFunc(func(v *gocui.View, key gocui.Key, ch rune, mod gocui.Modifier) {
+ return
+ })}
+}
+
func (p position) getCoordinate(max int) int {
return int(p.pct*float32(max)) + p.abs
}
-func setView(g *gocui.Gui, maxX, maxY int, viewName string) (*gocui.View, error) {
+func setView(g *gocui.Gui, viewName string) (*gocui.View, error) {
+ maxX, maxY := g.Size()
position := VIEW_POSITIONS[viewName]
return g.SetView(viewName,
- position.x0.getCoordinate(maxX),
- position.y0.getCoordinate(maxY),
- position.x1.getCoordinate(maxX),
- position.y1.getCoordinate(maxY))
+ position.x0.getCoordinate(maxX+1),
+ position.y0.getCoordinate(maxY+1),
+ position.x1.getCoordinate(maxX+1),
+ position.y1.getCoordinate(maxY+1))
}
func (a *App) Layout(g *gocui.Gui) error {
maxX, maxY := g.Size()
- maxX++
- maxY++
- if maxX-1 < MIN_WIDTH || maxY-1 < MIN_HEIGHT {
- if v, err := setView(g, maxX, maxY, ERROR_VIEW); err != nil {
+ if maxX < MIN_WIDTH || maxY < MIN_HEIGHT {
+ if v, err := setView(g, ERROR_VIEW); err != nil {
if err != gocui.ErrUnknownView {
return err
}
@@ -315,94 +387,45 @@ func (a *App) Layout(g *gocui.Gui) error {
a.setView(g)
}
- if v, err := setView(g, maxX, maxY, URL_VIEW); err != nil {
- if err != gocui.ErrUnknownView {
- return err
- }
- setViewDefaults(v)
- v.Title = VIEW_TITLES[URL_VIEW]
- v.Editable = true
- v.Overwrite = false
- v.Editor = &singleLineEditor{&defaultEditor}
- setViewTextAndCursor(v, a.config.General.DefaultURLScheme+"://")
+ for _, name := range []string{RESPONSE_HEADERS_VIEW, RESPONSE_BODY_VIEW} {
+ vp := VIEW_PROPERTIES[name]
+ vp.editor = a.getResponseViewEditor(g)
+ VIEW_PROPERTIES[name] = vp
}
- if v, err := setView(g, maxX, maxY, URL_PARAMS_VIEW); err != nil {
- if err != gocui.ErrUnknownView {
- return err
- }
- setViewDefaults(v)
- v.Editable = true
- v.Title = VIEW_TITLES[URL_PARAMS_VIEW]
- v.Editor = &defaultEditor
- }
- if v, err := setView(g, maxX, maxY, REQUEST_METHOD_VIEW); err != nil {
- if err != gocui.ErrUnknownView {
- return err
- }
- setViewDefaults(v)
- v.Editable = true
- v.Title = VIEW_TITLES[REQUEST_METHOD_VIEW]
- v.Editor = &singleLineEditor{&defaultEditor}
- setViewTextAndCursor(v, DEFAULT_METHOD)
- }
- if v, err := setView(g, maxX, maxY, REQUEST_DATA_VIEW); err != nil {
- if err != gocui.ErrUnknownView {
- return err
- }
- setViewDefaults(v)
- v.Editable = true
- v.Title = VIEW_TITLES[REQUEST_DATA_VIEW]
- v.Editor = &defaultEditor
- }
- if v, err := setView(g, maxX, maxY, REQUEST_HEADERS_VIEW); err != nil {
- if err != gocui.ErrUnknownView {
- return err
- }
- setViewDefaults(v)
- v.Editable = true
- v.Title = VIEW_TITLES[REQUEST_HEADERS_VIEW]
- v.Editor = &defaultEditor
- }
- if v, err := setView(g, maxX, maxY, RESPONSE_HEADERS_VIEW); err != nil {
- if err != gocui.ErrUnknownView {
- return err
+ for _, name := range []string{
+ URL_VIEW,
+ URL_PARAMS_VIEW,
+ REQUEST_METHOD_VIEW,
+ REQUEST_DATA_VIEW,
+ REQUEST_HEADERS_VIEW,
+ RESPONSE_HEADERS_VIEW,
+ RESPONSE_BODY_VIEW,
+ SEARCH_PROMPT_VIEW,
+ SEARCH_VIEW,
+ } {
+ if v, err := setView(g, name); err != nil {
+ if err != gocui.ErrUnknownView {
+ return err
+ }
+ v.Title = VIEW_PROPERTIES[name].title
+ v.Frame = VIEW_PROPERTIES[name].frame
+ v.Editable = VIEW_PROPERTIES[name].editable
+ v.Wrap = VIEW_PROPERTIES[name].wrap
+ v.Editor = VIEW_PROPERTIES[name].editor
}
- setViewDefaults(v)
- v.Wrap = true
- v.Title = VIEW_TITLES[RESPONSE_HEADERS_VIEW]
- v.Editable = true
- v.Editor = &ViewEditor{a, g, false, gocui.EditorFunc(func(v *gocui.View, key gocui.Key, ch rune, mod gocui.Modifier) {
- return
- })}
}
- if v, err := setView(g, maxX, maxY, RESPONSE_BODY_VIEW); err != nil {
- if err != gocui.ErrUnknownView {
- return err
- }
- setViewDefaults(v)
- v.Wrap = true
- v.Title = VIEW_TITLES[RESPONSE_BODY_VIEW]
- v.Editable = true
- v.Editor = &ViewEditor{a, g, false, gocui.EditorFunc(func(v *gocui.View, key gocui.Key, ch rune, mod gocui.Modifier) {
- return
- })}
+
+ if v, err := g.View(URL_VIEW); err == nil {
+ setViewTextAndCursor(v, a.config.General.DefaultURLScheme+"://")
}
- if v, err := setView(g, maxX, maxY, PROMPT); err != nil {
- if err != gocui.ErrUnknownView {
- return err
- }
- v.Frame = false
- setViewTextAndCursor(v, VIEW_TITLES[SEARCH_VIEW])
+ if v, err := g.View(REQUEST_METHOD_VIEW); err == nil {
+ setViewTextAndCursor(v, DEFAULT_METHOD)
}
- if v, err := setView(g, maxX, maxY, SEARCH_VIEW); err != nil {
- if err != gocui.ErrUnknownView {
- return err
- }
- v.Frame = false
- v.Editable = true
- v.Editor = &singleLineEditor{&SearchEditor{&defaultEditor}}
+ if v, err := g.View(SEARCH_PROMPT_VIEW); err == nil {
+ setViewTextAndCursor(v, SEARCH_PROMPT)
}
+
return nil
}
@@ -435,15 +458,12 @@ func (a *App) setViewByName(g *gocui.Gui, name string) error {
func popup(g *gocui.Gui, msg string) {
var popup *gocui.View
var err error
- maxX, maxY := g.Size()
- maxX++
- maxY++
p := VIEW_POSITIONS[POPUP_VIEW]
p.x0.abs = -len(msg)/2 - 1
p.x1.abs = len(msg)/2 + 1
VIEW_POSITIONS[POPUP_VIEW] = p
- if popup, err = setView(g, maxX, maxY, POPUP_VIEW); err != nil {
+ if popup, err = setView(g, POPUP_VIEW); err != nil {
if err != gocui.ErrUnknownView {
return
}
@@ -761,7 +781,7 @@ func (a *App) SetKeys(g *gocui.Gui) error {
if err != nil {
return err
}
- help.Title = "Help"
+ help.Title = VIEW_TITLES[HELP_VIEW]
help.Highlight = false
fmt.Fprint(help, "Keybindings:\n")
a.printViewKeybindings(help, "global")
@@ -1199,7 +1219,7 @@ func getViewValue(g *gocui.Gui, name string) string {
func setViewDefaults(v *gocui.View) {
v.Frame = true
- v.Wrap = false
+ v.Wrap = true
}
func setViewTextAndCursor(v *gocui.View, s string) {
From 221de5ac8963928537b24fa68e45900965575956 Mon Sep 17 00:00:00 2001
From: Pawel Wolowiec
Date: Fri, 17 Feb 2017 01:00:01 +0100
Subject: [PATCH 04/15] run gofmt
---
wuzz.go | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/wuzz.go b/wuzz.go
index 86e41ad..9ae69c7 100644
--- a/wuzz.go
+++ b/wuzz.go
@@ -392,7 +392,7 @@ func (a *App) Layout(g *gocui.Gui) error {
vp.editor = a.getResponseViewEditor(g)
VIEW_PROPERTIES[name] = vp
}
-
+
for _, name := range []string{
URL_VIEW,
URL_PARAMS_VIEW,
From 352a9df4b606ee48baed97033af602d23779e65b Mon Sep 17 00:00:00 2001
From: Pawel Wolowiec
Date: Fri, 17 Feb 2017 00:22:58 +0100
Subject: [PATCH 05/15] Moved most view properties to the top, leaving Layout
function much smaller
---
wuzz.go | 247 ++++++++++++++++++++++++++++++--------------------------
1 file changed, 133 insertions(+), 114 deletions(-)
diff --git a/wuzz.go b/wuzz.go
index 45a85fd..bb9abda 100644
--- a/wuzz.go
+++ b/wuzz.go
@@ -22,7 +22,6 @@ import (
"github.com/asciimoo/wuzz/config"
"crypto/tls"
-
"github.com/jroimartin/gocui"
"github.com/mattn/go-runewidth"
"github.com/nwidger/jsoncolor"
@@ -32,6 +31,7 @@ const VERSION = "0.2.0"
const TIMEOUT_DURATION = 5 // in seconds
const WINDOWS_OS = "windows"
+const SEARCH_PROMPT = "search> "
const (
ALL_VIEWS = ""
@@ -45,31 +45,23 @@ const (
RESPONSE_HEADERS_VIEW = "response-headers"
RESPONSE_BODY_VIEW = "response-body"
- PROMPT = "prompt"
- POPUP_VIEW = "popup_view"
- ERROR_VIEW = "error_view"
- HISTORY_VIEW = "history"
- SAVE_DIALOG_VIEW = "save-dialog"
- SAVE_RESULT_VIEW = "save-result"
- METHOD_LIST_VIEW = "method-list"
- HELP_VIEW = "help"
+ SEARCH_PROMPT_VIEW = "prompt"
+ POPUP_VIEW = "popup_view"
+ ERROR_VIEW = "error_view"
+ HISTORY_VIEW = "history"
+ SAVE_DIALOG_VIEW = "save-dialog"
+ SAVE_RESULT_VIEW = "save-result"
+ METHOD_LIST_VIEW = "method-list"
+ HELP_VIEW = "help"
)
var VIEW_TITLES = map[string]string{
- URL_VIEW: "URL - press F1 for help",
- URL_PARAMS_VIEW: "URL params",
- REQUEST_METHOD_VIEW: "Method",
- REQUEST_DATA_VIEW: "Request data (POST/PUT/PATCH)",
- REQUEST_HEADERS_VIEW: "Request headers",
- SEARCH_VIEW: "search> ",
- RESPONSE_HEADERS_VIEW: "Response headers",
- RESPONSE_BODY_VIEW: "Response body",
-
POPUP_VIEW: "Info",
ERROR_VIEW: "Error",
HISTORY_VIEW: "History",
SAVE_DIALOG_VIEW: "Save Response (enter to submit, ctrl+q to cancel)",
METHOD_LIST_VIEW: "Methods",
+ HELP_VIEW: "Help",
}
type position struct {
@@ -128,7 +120,7 @@ var VIEW_POSITIONS = map[string]viewPosition{
position{0.0, 0},
position{1.0, -2},
position{1.0, -2}},
- PROMPT: {
+ SEARCH_PROMPT_VIEW: {
position{0.0, -1},
position{1.0, -3},
position{0.0, 8},
@@ -140,6 +132,80 @@ var VIEW_POSITIONS = map[string]viewPosition{
position{0.5, 1}},
}
+type viewProperties struct {
+ title string
+ frame bool
+ editable bool
+ wrap bool
+ editor gocui.Editor
+}
+
+var VIEW_PROPERTIES = map[string]viewProperties{
+ URL_VIEW: {
+ title: "URL - press F1 for help",
+ frame: true,
+ editable: true,
+ wrap: true,
+ editor: &singleLineEditor{&defaultEditor},
+ },
+ URL_PARAMS_VIEW: {
+ title: "URL params",
+ frame: true,
+ editable: true,
+ wrap: true,
+ editor: &defaultEditor,
+ },
+ REQUEST_METHOD_VIEW: {
+ title: "Method",
+ frame: true,
+ editable: true,
+ wrap: true,
+ editor: &singleLineEditor{&defaultEditor},
+ },
+ REQUEST_DATA_VIEW: {
+ title: "Request data (POST/PUT)",
+ frame: true,
+ editable: true,
+ wrap: true,
+ editor: &defaultEditor,
+ },
+ REQUEST_HEADERS_VIEW: {
+ title: "Request headers",
+ frame: true,
+ editable: true,
+ wrap: false,
+ editor: &defaultEditor,
+ },
+ RESPONSE_HEADERS_VIEW: {
+ title: "Response headers",
+ frame: true,
+ editable: true,
+ wrap: true,
+ editor: nil, // should be set using a.getViewEditor(g)
+ },
+ RESPONSE_BODY_VIEW: {
+ title: "Response body",
+ frame: true,
+ editable: true,
+ wrap: true,
+ editor: nil, // should be set using a.getViewEditor(g)
+ },
+ SEARCH_VIEW: {
+ title: "",
+ frame: false,
+ editable: true,
+ wrap: true,
+ editor: &singleLineEditor{&SearchEditor{&defaultEditor}},
+ },
+ SEARCH_PROMPT_VIEW: {
+ title: "",
+ frame: false,
+ editable: false,
+ wrap: true,
+ editor: nil,
+ },
+}
+
var METHODS []string = []string{
http.MethodGet,
http.MethodPost,
@@ -279,26 +345,31 @@ func (e singleLineEditor) Edit(v *gocui.View, key gocui.Key, ch rune, mod gocui.
//
+func (a *App) getResponseViewEditor(g *gocui.Gui) gocui.Editor {
+ return &ViewEditor{a, g, false, gocui.EditorFunc(func(v *gocui.View, key gocui.Key, ch rune, mod gocui.Modifier) {
+ return
+ })}
+}
+
func (p position) getCoordinate(max int) int {
return int(p.pct*float32(max)) + p.abs
}
-func setView(g *gocui.Gui, maxX, maxY int, viewName string) (*gocui.View, error) {
+func setView(g *gocui.Gui, viewName string) (*gocui.View, error) {
+ maxX, maxY := g.Size()
position := VIEW_POSITIONS[viewName]
return g.SetView(viewName,
- position.x0.getCoordinate(maxX),
- position.y0.getCoordinate(maxY),
- position.x1.getCoordinate(maxX),
- position.y1.getCoordinate(maxY))
+ position.x0.getCoordinate(maxX+1),
+ position.y0.getCoordinate(maxY+1),
+ position.x1.getCoordinate(maxX+1),
+ position.y1.getCoordinate(maxY+1))
}
func (a *App) Layout(g *gocui.Gui) error {
maxX, maxY := g.Size()
- maxX++
- maxY++
- if maxX-1 < MIN_WIDTH || maxY-1 < MIN_HEIGHT {
- if v, err := setView(g, maxX, maxY, ERROR_VIEW); err != nil {
+ if maxX < MIN_WIDTH || maxY < MIN_HEIGHT {
+ if v, err := setView(g, ERROR_VIEW); err != nil {
if err != gocui.ErrUnknownView {
return err
}
@@ -315,94 +386,45 @@ func (a *App) Layout(g *gocui.Gui) error {
a.setView(g)
}
- if v, err := setView(g, maxX, maxY, URL_VIEW); err != nil {
- if err != gocui.ErrUnknownView {
- return err
- }
- setViewDefaults(v)
- v.Title = VIEW_TITLES[URL_VIEW]
- v.Editable = true
- v.Overwrite = false
- v.Editor = &singleLineEditor{&defaultEditor}
- setViewTextAndCursor(v, a.config.General.DefaultURLScheme+"://")
+ for _, name := range []string{RESPONSE_HEADERS_VIEW, RESPONSE_BODY_VIEW} {
+ vp := VIEW_PROPERTIES[name]
+ vp.editor = a.getResponseViewEditor(g)
+ VIEW_PROPERTIES[name] = vp
}
- if v, err := setView(g, maxX, maxY, URL_PARAMS_VIEW); err != nil {
- if err != gocui.ErrUnknownView {
- return err
- }
- setViewDefaults(v)
- v.Editable = true
- v.Title = VIEW_TITLES[URL_PARAMS_VIEW]
- v.Editor = &defaultEditor
- }
- if v, err := setView(g, maxX, maxY, REQUEST_METHOD_VIEW); err != nil {
- if err != gocui.ErrUnknownView {
- return err
- }
- setViewDefaults(v)
- v.Editable = true
- v.Title = VIEW_TITLES[REQUEST_METHOD_VIEW]
- v.Editor = &singleLineEditor{&defaultEditor}
- setViewTextAndCursor(v, DEFAULT_METHOD)
- }
- if v, err := setView(g, maxX, maxY, REQUEST_DATA_VIEW); err != nil {
- if err != gocui.ErrUnknownView {
- return err
- }
- setViewDefaults(v)
- v.Editable = true
- v.Title = VIEW_TITLES[REQUEST_DATA_VIEW]
- v.Editor = &defaultEditor
- }
- if v, err := setView(g, maxX, maxY, REQUEST_HEADERS_VIEW); err != nil {
- if err != gocui.ErrUnknownView {
- return err
- }
- setViewDefaults(v)
- v.Editable = true
- v.Title = VIEW_TITLES[REQUEST_HEADERS_VIEW]
- v.Editor = &defaultEditor
- }
- if v, err := setView(g, maxX, maxY, RESPONSE_HEADERS_VIEW); err != nil {
- if err != gocui.ErrUnknownView {
- return err
+ for _, name := range []string{
+ URL_VIEW,
+ URL_PARAMS_VIEW,
+ REQUEST_METHOD_VIEW,
+ REQUEST_DATA_VIEW,
+ REQUEST_HEADERS_VIEW,
+ RESPONSE_HEADERS_VIEW,
+ RESPONSE_BODY_VIEW,
+ SEARCH_PROMPT_VIEW,
+ SEARCH_VIEW,
+ } {
+ if v, err := setView(g, name); err != nil {
+ if err != gocui.ErrUnknownView {
+ return err
+ }
+ v.Title = VIEW_PROPERTIES[name].title
+ v.Frame = VIEW_PROPERTIES[name].frame
+ v.Editable = VIEW_PROPERTIES[name].editable
+ v.Wrap = VIEW_PROPERTIES[name].wrap
+ v.Editor = VIEW_PROPERTIES[name].editor
}
- setViewDefaults(v)
- v.Wrap = true
- v.Title = VIEW_TITLES[RESPONSE_HEADERS_VIEW]
- v.Editable = true
- v.Editor = &ViewEditor{a, g, false, gocui.EditorFunc(func(v *gocui.View, key gocui.Key, ch rune, mod gocui.Modifier) {
- return
- })}
}
- if v, err := setView(g, maxX, maxY, RESPONSE_BODY_VIEW); err != nil {
- if err != gocui.ErrUnknownView {
- return err
- }
- setViewDefaults(v)
- v.Wrap = true
- v.Title = VIEW_TITLES[RESPONSE_BODY_VIEW]
- v.Editable = true
- v.Editor = &ViewEditor{a, g, false, gocui.EditorFunc(func(v *gocui.View, key gocui.Key, ch rune, mod gocui.Modifier) {
- return
- })}
+
+ if v, err := g.View(URL_VIEW); err == nil {
+ setViewTextAndCursor(v, a.config.General.DefaultURLScheme+"://")
}
- if v, err := setView(g, maxX, maxY, PROMPT); err != nil {
- if err != gocui.ErrUnknownView {
- return err
- }
- v.Frame = false
- setViewTextAndCursor(v, VIEW_TITLES[SEARCH_VIEW])
+ if v, err := g.View(REQUEST_METHOD_VIEW); err == nil {
+ setViewTextAndCursor(v, DEFAULT_METHOD)
}
- if v, err := setView(g, maxX, maxY, SEARCH_VIEW); err != nil {
- if err != gocui.ErrUnknownView {
- return err
- }
- v.Frame = false
- v.Editable = true
- v.Editor = &singleLineEditor{&SearchEditor{&defaultEditor}}
+ if v, err := g.View(SEARCH_PROMPT_VIEW); err == nil {
+ setViewTextAndCursor(v, SEARCH_PROMPT)
}
+
return nil
}
@@ -435,15 +457,12 @@ func (a *App) setViewByName(g *gocui.Gui, name string) error {
func popup(g *gocui.Gui, msg string) {
var popup *gocui.View
var err error
- maxX, maxY := g.Size()
- maxX++
- maxY++
p := VIEW_POSITIONS[POPUP_VIEW]
p.x0.abs = -len(msg)/2 - 1
p.x1.abs = len(msg)/2 + 1
VIEW_POSITIONS[POPUP_VIEW] = p
- if popup, err = setView(g, maxX, maxY, POPUP_VIEW); err != nil {
+ if popup, err = setView(g, POPUP_VIEW); err != nil {
if err != gocui.ErrUnknownView {
return
}
@@ -761,7 +780,7 @@ func (a *App) SetKeys(g *gocui.Gui) error {
if err != nil {
return err
}
- help.Title = "Help"
+ help.Title = VIEW_TITLES[HELP_VIEW]
help.Highlight = false
fmt.Fprint(help, "Keybindings:\n")
a.printViewKeybindings(help, "global")
From 112e85f4b4564d76d33c9512e77acae13cc5e898 Mon Sep 17 00:00:00 2001
From: Adam Tauber
Date: Fri, 17 Feb 2017 00:29:37 +0100
Subject: [PATCH 06/15] [fix] disable wrapping of editable views - related to
#61
---
wuzz.go | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/wuzz.go b/wuzz.go
index bb9abda..62b235d 100644
--- a/wuzz.go
+++ b/wuzz.go
@@ -163,7 +163,7 @@ var VIEW_PROPERTIES = map[string]viewProperties{
editor: &singleLineEditor{&defaultEditor},
},
REQUEST_DATA_VIEW: {
- title: "Request data (POST/PUT)",
+ title: "Request data (POST/PUT/PATCH)",
frame: true,
editable: true,
wrap: true,
From fa40a8d345048f05af3139be1fc043230bfa66f8 Mon Sep 17 00:00:00 2001
From: Pawel Wolowiec
Date: Fri, 17 Feb 2017 00:45:16 +0100
Subject: [PATCH 07/15] Moved most view properties to the top, leaving Layout
function much smaller
2nd commit due to master changes
---
wuzz.go | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/wuzz.go b/wuzz.go
index 62b235d..3dd9c69 100644
--- a/wuzz.go
+++ b/wuzz.go
@@ -145,28 +145,28 @@ var VIEW_PROPERTIES = map[string]viewProperties{
title: "URL - press F1 for help",
frame: true,
editable: true,
- wrap: true,
+ wrap: false,
editor: &singleLineEditor{&defaultEditor},
},
URL_PARAMS_VIEW: {
title: "URL params",
frame: true,
editable: true,
- wrap: true,
+ wrap: false,
editor: &defaultEditor,
},
REQUEST_METHOD_VIEW: {
title: "Method",
frame: true,
editable: true,
- wrap: true,
+ wrap: false,
editor: &singleLineEditor{&defaultEditor},
},
REQUEST_DATA_VIEW: {
title: "Request data (POST/PUT/PATCH)",
frame: true,
editable: true,
- wrap: true,
+ wrap: false,
editor: &defaultEditor,
},
REQUEST_HEADERS_VIEW: {
@@ -194,14 +194,14 @@ var VIEW_PROPERTIES = map[string]viewProperties{
title: "",
frame: false,
editable: true,
- wrap: true,
+ wrap: false,
editor: &singleLineEditor{&SearchEditor{&defaultEditor}},
},
SEARCH_PROMPT_VIEW: {
title: "",
frame: false,
editable: false,
- wrap: true,
+ wrap: false,
editor: nil,
},
}
From 06dbce4750a17cd7297dc13f06492bed4677e60e Mon Sep 17 00:00:00 2001
From: Pawel Wolowiec
Date: Sun, 19 Feb 2017 19:52:19 +0100
Subject: [PATCH 08/15] Fixed error that unabled editing URL + minor refactor
---
wuzz.go | 77 ++++++++++++++++++++++++++++++++-------------------------
1 file changed, 43 insertions(+), 34 deletions(-)
diff --git a/wuzz.go b/wuzz.go
index 3dd9c69..ad6ff96 100644
--- a/wuzz.go
+++ b/wuzz.go
@@ -138,6 +138,7 @@ type viewProperties struct {
editable bool
wrap bool
editor gocui.Editor
+ text string
}
var VIEW_PROPERTIES = map[string]viewProperties{
@@ -161,6 +162,7 @@ var VIEW_PROPERTIES = map[string]viewProperties{
editable: true,
wrap: false,
editor: &singleLineEditor{&defaultEditor},
+ text: DEFAULT_METHOD,
},
REQUEST_DATA_VIEW: {
title: "Request data (POST/PUT/PATCH)",
@@ -203,10 +205,18 @@ var VIEW_PROPERTIES = map[string]viewProperties{
editable: false,
wrap: false,
editor: nil,
+ text: SEARCH_PROMPT,
+ },
+ POPUP_VIEW: {
+ title: "Info",
+ frame: true,
+ editable: false,
+ wrap: false,
+ editor: nil,
},
}
-var METHODS []string = []string{
+var METHODS = []string{
http.MethodGet,
http.MethodPost,
http.MethodPut,
@@ -220,14 +230,14 @@ var METHODS []string = []string{
const DEFAULT_METHOD = http.MethodGet
-var CLIENT *http.Client = &http.Client{
+var CLIENT = &http.Client{
Timeout: time.Duration(TIMEOUT_DURATION * time.Second),
}
-var TRANSPORT *http.Transport = &http.Transport{
+var TRANSPORT = &http.Transport{
Proxy: http.ProxyFromEnvironment,
}
-var VIEWS []string = []string{
+var VIEWS = []string{
URL_VIEW,
URL_PARAMS_VIEW,
REQUEST_METHOD_VIEW,
@@ -275,7 +285,7 @@ type SearchEditor struct {
wuzzEditor *ViewEditor
}
-// The singleLineEditor removes multilines capabilities
+// The singleLineEditor removes multi lines capabilities
type singleLineEditor struct {
wuzzEditor gocui.Editor
}
@@ -314,7 +324,7 @@ func (e *SearchEditor) Edit(v *gocui.View, key gocui.Key, ch rune, mod gocui.Mod
})
}
-// The singleLineEditor removes multilines capabilities
+// The singleLineEditor removes multi lines capabilities
func (e singleLineEditor) Edit(v *gocui.View, key gocui.Key, ch rune, mod gocui.Modifier) {
switch {
case (ch != 0 || key == gocui.KeySpace) && mod == 0:
@@ -365,6 +375,15 @@ func setView(g *gocui.Gui, viewName string) (*gocui.View, error) {
position.y1.getCoordinate(maxY+1))
}
+func setViewProperties(v *gocui.View, name string) {
+ v.Title = VIEW_PROPERTIES[name].title
+ v.Frame = VIEW_PROPERTIES[name].frame
+ v.Editable = VIEW_PROPERTIES[name].editable
+ v.Wrap = VIEW_PROPERTIES[name].wrap
+ v.Editor = VIEW_PROPERTIES[name].editor
+ setViewTextAndCursor(v, VIEW_PROPERTIES[name].text)
+}
+
func (a *App) Layout(g *gocui.Gui) error {
maxX, maxY := g.Size()
@@ -392,6 +411,10 @@ func (a *App) Layout(g *gocui.Gui) error {
VIEW_PROPERTIES[name] = vp
}
+ p := VIEW_PROPERTIES[URL_VIEW]
+ p.text = a.config.General.DefaultURLScheme + "://"
+ VIEW_PROPERTIES[URL_VIEW] = p
+
for _, name := range []string{
URL_VIEW,
URL_PARAMS_VIEW,
@@ -407,24 +430,10 @@ func (a *App) Layout(g *gocui.Gui) error {
if err != gocui.ErrUnknownView {
return err
}
- v.Title = VIEW_PROPERTIES[name].title
- v.Frame = VIEW_PROPERTIES[name].frame
- v.Editable = VIEW_PROPERTIES[name].editable
- v.Wrap = VIEW_PROPERTIES[name].wrap
- v.Editor = VIEW_PROPERTIES[name].editor
+ setViewProperties(v, name)
}
}
- if v, err := g.View(URL_VIEW); err == nil {
- setViewTextAndCursor(v, a.config.General.DefaultURLScheme+"://")
- }
- if v, err := g.View(REQUEST_METHOD_VIEW); err == nil {
- setViewTextAndCursor(v, DEFAULT_METHOD)
- }
- if v, err := g.View(SEARCH_PROMPT_VIEW); err == nil {
- setViewTextAndCursor(v, SEARCH_PROMPT)
- }
-
return nil
}
@@ -455,20 +464,20 @@ func (a *App) setViewByName(g *gocui.Gui, name string) error {
}
func popup(g *gocui.Gui, msg string) {
- var popup *gocui.View
- var err error
-
- p := VIEW_POSITIONS[POPUP_VIEW]
- p.x0.abs = -len(msg)/2 - 1
- p.x1.abs = len(msg)/2 + 1
- VIEW_POSITIONS[POPUP_VIEW] = p
- if popup, err = setView(g, POPUP_VIEW); err != nil {
+ pos := VIEW_POSITIONS[POPUP_VIEW]
+ pos.x0.abs = -len(msg)/2 - 1
+ pos.x1.abs = len(msg)/2 + 1
+ VIEW_POSITIONS[POPUP_VIEW] = pos
+
+ p := VIEW_PROPERTIES[POPUP_VIEW]
+ p.text = msg
+ VIEW_PROPERTIES[POPUP_VIEW] = p
+
+ if v, err := setView(g, POPUP_VIEW); err != nil {
if err != gocui.ErrUnknownView {
return
}
- setViewDefaults(popup)
- popup.Title = VIEW_TITLES[POPUP_VIEW]
- setViewTextAndCursor(popup, msg)
+ setViewProperties(v, POPUP_VIEW)
g.SetViewOnTop(POPUP_VIEW)
}
}
@@ -603,7 +612,7 @@ func (a *App) SubmitRequest(g *gocui.Gui, _ *gocui.View) error {
// print status code and sorted headers
hkeys := make([]string, 0, len(response.Header))
- for hname, _ := range response.Header {
+ for hname := range response.Header {
hkeys = append(hkeys, hname)
}
sort.Strings(hkeys)
@@ -746,7 +755,7 @@ func (a *App) printViewKeybindings(v io.Writer, viewName string) {
}
mk := make([]string, len(keys))
i := 0
- for k, _ := range keys {
+ for k := range keys {
mk[i] = k
i++
}
From 738df991cd6c764f07cbdfc9ceb4df2e157cfe39 Mon Sep 17 00:00:00 2001
From: Pawel Wolowiec
Date: Mon, 20 Feb 2017 02:55:14 +0100
Subject: [PATCH 09/15] Refactored SubmitRequest() function + fixed a bug,
where response headers would display twice + other minor refactorings
---
wuzz.go | 466 ++++++++++++++++++++++++++++++--------------------------
1 file changed, 254 insertions(+), 212 deletions(-)
diff --git a/wuzz.go b/wuzz.go
index ad6ff96..22d4a7a 100644
--- a/wuzz.go
+++ b/wuzz.go
@@ -55,15 +55,6 @@ const (
HELP_VIEW = "help"
)
-var VIEW_TITLES = map[string]string{
- POPUP_VIEW: "Info",
- ERROR_VIEW: "Error",
- HISTORY_VIEW: "History",
- SAVE_DIALOG_VIEW: "Save Response (enter to submit, ctrl+q to cancel)",
- METHOD_LIST_VIEW: "Methods",
- HELP_VIEW: "Help",
-}
-
type position struct {
// value = prc * MAX + abs
pct float32
@@ -207,6 +198,13 @@ var VIEW_PROPERTIES = map[string]viewProperties{
editor: nil,
text: SEARCH_PROMPT,
},
+ ERROR_VIEW: {
+ title: "Error",
+ frame: true,
+ editable: false,
+ wrap: false,
+ editor: nil,
+ },
POPUP_VIEW: {
title: "Info",
frame: true,
@@ -214,6 +212,18 @@ var VIEW_PROPERTIES = map[string]viewProperties{
wrap: false,
editor: nil,
},
+ HISTORY_VIEW: {
+ title: "History",
+ },
+ SAVE_DIALOG_VIEW: {
+ title: "Save Response (enter to submit, ctrl+q to cancel)",
+ },
+ METHOD_LIST_VIEW: {
+ title: "Methods",
+ },
+ HELP_VIEW: {
+ title: "Help",
+ },
}
var METHODS = []string{
@@ -385,52 +395,50 @@ func setViewProperties(v *gocui.View, name string) {
}
func (a *App) Layout(g *gocui.Gui) error {
- maxX, maxY := g.Size()
-
- if maxX < MIN_WIDTH || maxY < MIN_HEIGHT {
+ if maxX, maxY := g.Size(); maxX < MIN_WIDTH || maxY < MIN_HEIGHT {
if v, err := setView(g, ERROR_VIEW); err != nil {
if err != gocui.ErrUnknownView {
return err
}
- setViewDefaults(v)
- v.Title = VIEW_TITLES[ERROR_VIEW]
+ setViewProperties(v, ERROR_VIEW)
+
g.Cursor = false
fmt.Fprintln(v, "Terminal is too small")
}
- return nil
- }
- if _, err := g.View(ERROR_VIEW); err == nil {
- g.DeleteView(ERROR_VIEW)
- g.Cursor = true
- a.setView(g)
- }
+ } else {
+ if _, err := g.View(ERROR_VIEW); err == nil {
+ g.DeleteView(ERROR_VIEW)
+ g.Cursor = true
+ a.setView(g)
+ }
- for _, name := range []string{RESPONSE_HEADERS_VIEW, RESPONSE_BODY_VIEW} {
- vp := VIEW_PROPERTIES[name]
- vp.editor = a.getResponseViewEditor(g)
- VIEW_PROPERTIES[name] = vp
- }
+ for _, name := range []string{RESPONSE_HEADERS_VIEW, RESPONSE_BODY_VIEW} {
+ vp := VIEW_PROPERTIES[name]
+ vp.editor = a.getResponseViewEditor(g)
+ VIEW_PROPERTIES[name] = vp
+ }
- p := VIEW_PROPERTIES[URL_VIEW]
- p.text = a.config.General.DefaultURLScheme + "://"
- VIEW_PROPERTIES[URL_VIEW] = p
-
- for _, name := range []string{
- URL_VIEW,
- URL_PARAMS_VIEW,
- REQUEST_METHOD_VIEW,
- REQUEST_DATA_VIEW,
- REQUEST_HEADERS_VIEW,
- RESPONSE_HEADERS_VIEW,
- RESPONSE_BODY_VIEW,
- SEARCH_PROMPT_VIEW,
- SEARCH_VIEW,
- } {
- if v, err := setView(g, name); err != nil {
- if err != gocui.ErrUnknownView {
- return err
+ p := VIEW_PROPERTIES[URL_VIEW]
+ p.text = a.config.General.DefaultURLScheme + "://"
+ VIEW_PROPERTIES[URL_VIEW] = p
+
+ for _, name := range []string{
+ URL_VIEW,
+ URL_PARAMS_VIEW,
+ REQUEST_METHOD_VIEW,
+ REQUEST_DATA_VIEW,
+ REQUEST_HEADERS_VIEW,
+ RESPONSE_HEADERS_VIEW,
+ RESPONSE_BODY_VIEW,
+ SEARCH_PROMPT_VIEW,
+ SEARCH_VIEW,
+ } {
+ if v, err := setView(g, name); err != nil {
+ if err != gocui.ErrUnknownView {
+ return err
+ }
+ setViewProperties(v, name)
}
- setViewProperties(v, name)
}
}
@@ -463,7 +471,96 @@ func (a *App) setViewByName(g *gocui.Gui, name string) error {
return fmt.Errorf("View not found")
}
-func popup(g *gocui.Gui, msg string) {
+func (a *App) SubmitRequest(g *gocui.Gui, _ *gocui.View) error {
+ rhv, _ := g.View(RESPONSE_HEADERS_VIEW)
+ rhv.Clear()
+ rbv, _ := g.View(RESPONSE_BODY_VIEW)
+ rbv.Clear()
+
+ go a.CreateAndProcessRequest(g)
+
+ return nil
+}
+
+func (a *App) CreateAndProcessRequest(g *gocui.Gui) {
+ defer func() {
+ if r := recover(); r != nil {
+ displayErrorInResponseBody(g, r)
+ }
+ }()
+
+ displayInfo(g, "Sending request..")
+ defer g.DeleteView(POPUP_VIEW)
+
+ var r *Request = &Request{}
+
+ // get url
+ r.Url = getViewValue(g, URL_VIEW)
+ u := getUrlFromString(r.Url)
+
+ // get request method
+ r.Method = getViewValue(g, REQUEST_METHOD_VIEW)
+
+ // get params
+ p := getViewValue(g, URL_PARAMS_VIEW)
+ u.RawQuery = getQuery(p, u)
+ r.GetParams = u.RawQuery
+
+ // set headers
+ r.Headers = getViewValue(g, REQUEST_HEADERS_VIEW)
+ headers := getHttpHeaders(r.Headers)
+
+ // set body
+ body := getRequestBody(r.Method, g, headers)
+
+ // create request
+ request := getHttpRequest(r.Method, u, headers, body)
+
+ // do request
+ response := getHttpResponse(request)
+ defer response.Body.Close()
+
+ // set content type
+ r.ContentType = response.Header.Get("Content-Type")
+
+ // extract body
+ if response.Header.Get("Content-Encoding") == "gzip" {
+ reader, err := gzip.NewReader(response.Body)
+ if err != nil {
+ panic(fmt.Sprintf("Cannot uncompress response: %v", err))
+ }
+ defer reader.Close()
+ response.Body = reader
+ }
+
+ if bodyBytes, err := ioutil.ReadAll(response.Body); err == nil {
+ r.RawResponseBody = bodyBytes
+ }
+
+ responseHeaders := getSortedResponseHeaders(response)
+ r.ResponseHeaders = responseHeaders
+
+ // add to history
+ a.history = append(a.history, r)
+ a.historyIndex = len(a.history) - 1
+
+ // render response
+ g.Execute(func(g *gocui.Gui) error {
+ printResponseHeaders(g, responseHeaders)
+ a.PrintBody(g)
+ return nil
+ })
+}
+
+func displayErrorInResponseBody(g *gocui.Gui, a interface{}) {
+ g.Execute(func(g *gocui.Gui) error {
+ v, _ := g.View(RESPONSE_BODY_VIEW)
+ fmt.Fprint(v, a)
+ return nil
+ })
+}
+
+func displayInfo(g *gocui.Gui, msg string) {
pos := VIEW_POSITIONS[POPUP_VIEW]
pos.x0.abs = -len(msg)/2 - 1
pos.x1.abs = len(msg)/2 + 1
@@ -482,164 +579,108 @@ func popup(g *gocui.Gui, msg string) {
}
}
-func (a *App) SubmitRequest(g *gocui.Gui, _ *gocui.View) error {
- vrb, _ := g.View(RESPONSE_BODY_VIEW)
- vrb.Clear()
- vrh, _ := g.View(RESPONSE_HEADERS_VIEW)
- vrh.Clear()
- popup(g, "Sending request..")
-
- var r *Request = &Request{}
-
- go func(g *gocui.Gui, a *App, r *Request) error {
- defer g.DeleteView(POPUP_VIEW)
- // parse url
- r.Url = getViewValue(g, URL_VIEW)
- u, err := url.Parse(r.Url)
- if err != nil {
- g.Execute(func(g *gocui.Gui) error {
- vrb, _ := g.View(RESPONSE_BODY_VIEW)
- fmt.Fprintf(vrb, "URL parse error: %v", err)
- return nil
- })
- return nil
- }
-
- q, err := url.ParseQuery(strings.Replace(getViewValue(g, URL_PARAMS_VIEW), "\n", "&", -1))
- if err != nil {
- g.Execute(func(g *gocui.Gui) error {
- vrb, _ := g.View(RESPONSE_BODY_VIEW)
- fmt.Fprintf(vrb, "Invalid GET parameters: %v", err)
- return nil
- })
- return nil
- }
- originalQuery := u.Query()
- for k, v := range q {
- originalQuery.Add(k, strings.Join(v, ""))
- }
- u.RawQuery = originalQuery.Encode()
- r.GetParams = u.RawQuery
-
- // parse method
- r.Method = getViewValue(g, REQUEST_METHOD_VIEW)
-
- // set headers
- headers := http.Header{}
- headers.Set("User-Agent", "")
- r.Headers = getViewValue(g, REQUEST_HEADERS_VIEW)
- for _, header := range strings.Split(r.Headers, "\n") {
- if header != "" {
- header_parts := strings.SplitN(header, ": ", 2)
- if len(header_parts) != 2 {
- g.Execute(func(g *gocui.Gui) error {
- vrb, _ := g.View(RESPONSE_BODY_VIEW)
- fmt.Fprintf(vrb, "Invalid header: %v", header)
- return nil
- })
- return nil
- }
- headers.Set(header_parts[0], header_parts[1])
- }
- }
-
- var body io.Reader
-
- // parse POST/PUT/PATCH data
- if r.Method == http.MethodPost || r.Method == http.MethodPut || r.Method == http.MethodPatch {
- bodyStr := getViewValue(g, REQUEST_DATA_VIEW)
- if headers.Get("Content-Type") == "application/x-www-form-urlencoded" {
- bodyStr = strings.Replace(bodyStr, "\n", "&", -1)
- }
- body = bytes.NewBufferString(bodyStr)
- }
-
- // create request
- req, err := http.NewRequest(r.Method, u.String(), body)
- if err != nil {
- g.Execute(func(g *gocui.Gui) error {
- vrb, _ := g.View(RESPONSE_BODY_VIEW)
- fmt.Fprintf(vrb, "Request error: %v", err)
- return nil
- })
- return nil
- }
- req.Header = headers
+func getUrlFromString(urlString string) *url.URL {
+ u, err := url.Parse(urlString)
+ if err != nil {
+ panic(fmt.Sprintf("URL parse error: %v", err))
+ }
+ return u
+}
- // do request
- response, err := CLIENT.Do(req)
- if err != nil {
- g.Execute(func(g *gocui.Gui) error {
- vrb, _ := g.View(RESPONSE_BODY_VIEW)
- fmt.Fprintf(vrb, "Response error: %v", err)
- return nil
- })
- return nil
- }
- defer response.Body.Close()
+func getQuery(paramsString string, u *url.URL) string {
+ query, err := url.ParseQuery(strings.Replace(paramsString, "\n", "&", -1))
+ if err != nil {
+ panic(fmt.Sprintf("Invalid GET parameters: %v", err))
+ }
+ originalQuery := u.Query()
+ for k, v := range query {
+ originalQuery.Add(k, strings.Join(v, ""))
+ }
+ return originalQuery.Encode()
+}
- // extract body
- r.ContentType = response.Header.Get("Content-Type")
- if response.Header.Get("Content-Encoding") == "gzip" {
- reader, err := gzip.NewReader(response.Body)
- if err == nil {
- defer reader.Close()
- response.Body = reader
- } else {
- g.Execute(func(g *gocui.Gui) error {
- vrb, _ := g.View(RESPONSE_BODY_VIEW)
- fmt.Fprintf(vrb, "Cannot uncompress response: %v", err)
- return nil
- })
- return nil
+func getHttpHeaders(h string) http.Header {
+ headers := http.Header{}
+ headers.Set("User-Agent", "")
+ for _, header := range strings.Split(h, "\n") {
+ if header != "" {
+ header_parts := strings.SplitN(header, ": ", 2)
+ if len(header_parts) != 2 {
+ panic(fmt.Sprintf("Invalid header: %v", header))
}
+ headers.Set(header_parts[0], header_parts[1])
}
+ }
+ return headers
+}
- bodyBytes, err := ioutil.ReadAll(response.Body)
- if err == nil {
- r.RawResponseBody = bodyBytes
+func getRequestBody(method string, g *gocui.Gui, headers http.Header) io.Reader {
+ var body io.Reader
+ if method == http.MethodPost || method == http.MethodPut || method == http.MethodPatch {
+ bodyStr := getViewValue(g, REQUEST_DATA_VIEW)
+ if headers.Get("Content-Type") == "application/x-www-form-urlencoded" {
+ bodyStr = strings.Replace(bodyStr, "\n", "&", -1)
}
+ body = bytes.NewBufferString(bodyStr)
+ }
+ return body
+}
- // add to history
- a.history = append(a.history, r)
- a.historyIndex = len(a.history) - 1
+func getHttpRequest(method string, url *url.URL, headers http.Header, body io.Reader) *http.Request {
+ request, err := http.NewRequest(method, url.String(), body)
+ if err != nil {
+ panic(fmt.Sprintf("Request error: %v", err))
+ }
+ request.Header = headers
+ return request
+}
- // render response
- g.Execute(func(g *gocui.Gui) error {
- vrh, _ := g.View(RESPONSE_HEADERS_VIEW)
+func getHttpResponse(request *http.Request) *http.Response {
+ response, err := CLIENT.Do(request)
+ if err != nil {
+ panic(fmt.Sprintf("Response error: %v", err))
+ }
+ return response
+}
- a.PrintBody(g)
+func getSortedResponseHeaders(response *http.Response) string {
+ keys := make([]string, 0, len(response.Header))
+ for name := range response.Header {
+ keys = append(keys, name)
+ }
+ sort.Strings(keys)
+ status_color := statusCodeToColor(response.StatusCode)
+ headerString := fmt.Sprintf(
+ "\x1b[0;%dmHTTP/1.1 %v %v\x1b[0;0m\n",
+ status_color,
+ response.StatusCode,
+ http.StatusText(response.StatusCode),
+ )
+ for _, name := range keys {
+ headerString += fmt.Sprintf(
+ "\x1b[0;33m%v:\x1b[0;0m %v\n",
+ name,
+ strings.Join(response.Header[name], ","),
+ )
+ }
+ return headerString
+}
- // print status code and sorted headers
- hkeys := make([]string, 0, len(response.Header))
- for hname := range response.Header {
- hkeys = append(hkeys, hname)
- }
- sort.Strings(hkeys)
- status_color := 32
- if response.StatusCode != 200 {
- status_color = 31
- }
- header_str := fmt.Sprintf(
- "\x1b[0;%dmHTTP/1.1 %v %v\x1b[0;0m\n",
- status_color,
- response.StatusCode,
- http.StatusText(response.StatusCode),
- )
- for _, hname := range hkeys {
- header_str += fmt.Sprintf("\x1b[0;33m%v:\x1b[0;0m %v\n", hname, strings.Join(response.Header[hname], ","))
- }
- fmt.Fprint(vrh, header_str)
- if _, err := vrh.Line(0); err != nil {
- vrh.SetOrigin(0, 0)
- }
- r.ResponseHeaders = header_str
- return nil
- })
- return nil
- }(g, a, r)
+func statusCodeToColor(code int) int {
+ if code == 200 {
+ return 32
+ } else {
+ return 31
+ }
+}
- return nil
+func printResponseHeaders(g *gocui.Gui, headersString string) {
+ v, _ := g.View(RESPONSE_HEADERS_VIEW)
+ v.Clear()
+ fmt.Fprint(v, headersString)
+ if _, err := v.Line(0); err != nil {
+ v.SetOrigin(0, 0)
+ }
}
func (a *App) PrintBody(g *gocui.Gui) {
@@ -668,7 +709,7 @@ func (a *App) PrintBody(g *gocui.Gui) {
is_binary := strings.Index(req.ContentType, "text") == -1 && strings.Index(req.ContentType, "application") == -1
search_text := getViewValue(g, SEARCH_VIEW)
if search_text == "" || is_binary {
- vrb.Title = RESPONSE_BODY_VIEW
+ vrb.Title = VIEW_PROPERTIES[RESPONSE_BODY_VIEW].title
if is_binary {
vrb.Title += " [binary content]"
fmt.Fprint(vrb, hex.Dump(req.RawResponseBody))
@@ -789,7 +830,7 @@ func (a *App) SetKeys(g *gocui.Gui) error {
if err != nil {
return err
}
- help.Title = VIEW_TITLES[HELP_VIEW]
+ help.Title = VIEW_PROPERTIES[HELP_VIEW].title
help.Highlight = false
fmt.Fprint(help, "Keybindings:\n")
a.printViewKeybindings(help, "global")
@@ -941,16 +982,22 @@ func (a *App) CreatePopupView(name string, width, height int, g *gocui.Gui) (v *
if width > maxX-4 {
width = maxX - 4
}
- v, err = g.SetView(name, maxX/2-width/2-1, maxY/2-height/2-1, maxX/2+width/2, maxY/2+height/2+1)
- if err != nil && err != gocui.ErrUnknownView {
- return
+
+ VIEW_POSITIONS[name] = viewPosition{
+ position{0.5, -width/2 - 1},
+ position{0.5, -height/2 - 1},
+ position{0.5, width / 2},
+ position{0.5, height/2 + 1},
+ }
+ v, err = setView(g, name)
+ if err == nil || err == gocui.ErrUnknownView {
+ err = nil
+ v.Wrap = false
+ v.Frame = true
+ v.Highlight = true
+ v.SelFgColor = gocui.ColorYellow
+ a.currentPopup = name
}
- err = nil
- v.Wrap = false
- v.Frame = true
- v.Highlight = true
- v.SelFgColor = gocui.ColorYellow
- a.currentPopup = name
return
}
@@ -966,7 +1013,7 @@ func (a *App) ToggleHistory(g *gocui.Gui, _ *gocui.View) (err error) {
return
}
- history.Title = VIEW_TITLES[HISTORY_VIEW]
+ history.Title = VIEW_PROPERTIES[HISTORY_VIEW].title
if len(a.history) == 0 {
setViewTextAndCursor(history, "[!] No items in history")
@@ -1002,7 +1049,7 @@ func (a *App) ToggleMethodList(g *gocui.Gui, _ *gocui.View) (err error) {
if err != nil {
return
}
- method.Title = VIEW_TITLES[METHOD_LIST_VIEW]
+ method.Title = VIEW_PROPERTIES[METHOD_LIST_VIEW].title
cur := getViewValue(g, REQUEST_METHOD_VIEW)
@@ -1025,7 +1072,7 @@ func (a *App) OpenSaveDialog(g *gocui.Gui, _ *gocui.View) (err error) {
g.Cursor = true
- dialog.Title = VIEW_TITLES[SAVE_DIALOG_VIEW]
+ dialog.Title = VIEW_PROPERTIES[SAVE_DIALOG_VIEW].title
dialog.Editable = true
dialog.Wrap = false
@@ -1225,11 +1272,6 @@ func getViewValue(g *gocui.Gui, name string) string {
return strings.TrimSpace(v.Buffer())
}
-func setViewDefaults(v *gocui.View) {
- v.Frame = true
- v.Wrap = false
-}
-
func setViewTextAndCursor(v *gocui.View, s string) {
v.Clear()
fmt.Fprint(v, s)
From 12a7b517bfbf20060e84204920d86ddd622a2947 Mon Sep 17 00:00:00 2001
From: Pawel Wolowiec
Date: Mon, 20 Feb 2017 06:26:14 +0100
Subject: [PATCH 10/15] Refactored PrintBody() function
---
wuzz.go | 133 +++++++++++++++++++++++++++++++++++---------------------
1 file changed, 83 insertions(+), 50 deletions(-)
diff --git a/wuzz.go b/wuzz.go
index 22d4a7a..460c269 100644
--- a/wuzz.go
+++ b/wuzz.go
@@ -547,7 +547,7 @@ func (a *App) CreateAndProcessRequest(g *gocui.Gui) {
// render response
g.Execute(func(g *gocui.Gui) error {
printResponseHeaders(g, responseHeaders)
- a.PrintBody(g)
+ a.getAndPrintResponseBody(g)
return nil
})
}
@@ -685,60 +685,93 @@ func printResponseHeaders(g *gocui.Gui, headersString string) {
func (a *App) PrintBody(g *gocui.Gui) {
g.Execute(func(g *gocui.Gui) error {
- if len(a.history) == 0 {
- return nil
- }
- req := a.history[a.historyIndex]
- if req.RawResponseBody == nil {
- return nil
- }
- vrb, _ := g.View(RESPONSE_BODY_VIEW)
- vrb.Clear()
-
- responseBody := req.RawResponseBody
- // pretty-print json
- if strings.Contains(req.ContentType, "application/json") && a.config.General.FormatJSON {
- formatter := jsoncolor.NewFormatter()
- buf := bytes.NewBuffer(make([]byte, 0, len(req.RawResponseBody)))
- err := formatter.Format(buf, req.RawResponseBody)
- if err == nil {
- responseBody = buf.Bytes()
- }
- }
+ a.getAndPrintResponseBody(g)
+ return nil
+ })
+}
- is_binary := strings.Index(req.ContentType, "text") == -1 && strings.Index(req.ContentType, "application") == -1
- search_text := getViewValue(g, SEARCH_VIEW)
- if search_text == "" || is_binary {
- vrb.Title = VIEW_PROPERTIES[RESPONSE_BODY_VIEW].title
- if is_binary {
- vrb.Title += " [binary content]"
- fmt.Fprint(vrb, hex.Dump(req.RawResponseBody))
- } else {
- vrb.Write(responseBody)
- }
- if _, err := vrb.Line(0); !a.config.General.PreserveScrollPosition || err != nil {
- vrb.SetOrigin(0, 0)
+func (a *App) getAndPrintResponseBody(g *gocui.Gui) {
+ if len(a.history) == 0 {
+ return
+ }
+ req := a.history[a.historyIndex]
+ if req.RawResponseBody == nil {
+ return
+ }
+
+ title, body, shouldSetOrigin := getResponseBody(
+ getViewValue(g, SEARCH_VIEW),
+ req.RawResponseBody,
+ req.ContentType,
+ a.config.General,
+ )
+ printResponseBody(g, title, body, shouldSetOrigin)
+}
+
+func getResponseBody(
+ searchString string,
+ responseBody []byte,
+ contentType string,
+ generalAppOptions config.GeneralOptions) (title, body string, shouldSetOrigin bool) {
+
+ isText := strings.Contains(contentType, "text")
+ isApplication := strings.Contains(contentType, "application")
+ isJson := strings.Contains(contentType, "application/json")
+ isBinary := !(isText || isApplication)
+
+ title = VIEW_PROPERTIES[RESPONSE_BODY_VIEW].title
+ if searchString == "" || isBinary {
+ if isBinary {
+ title += " [binary content]"
+ body = hex.Dump(responseBody)
+ } else {
+ if isJson && generalAppOptions.FormatJSON {
+ responseBody = formatJson(responseBody)
}
- return nil
- }
- vrb.SetOrigin(0, 0)
- search_re, err := regexp.Compile(search_text)
- if err != nil {
- fmt.Fprint(vrb, "Error: invalid search regexp")
- return nil
+ body = string(responseBody)
}
- results := search_re.FindAll(req.RawResponseBody, 1000)
- if len(results) == 0 {
- vrb.Title = "No results"
- fmt.Fprint(vrb, "Error: no results")
- return nil
+ if !generalAppOptions.PreserveScrollPosition {
+ shouldSetOrigin = true
}
- vrb.Title = fmt.Sprintf("%d results", len(results))
- for _, result := range results {
- fmt.Fprintf(vrb, "-----\n%s\n", result)
+ } else {
+ shouldSetOrigin = true
+ if search_re, err := regexp.Compile(searchString); err != nil {
+ body = "Error: invalid search regexp"
+ } else {
+ results := search_re.FindAll(responseBody, 1000)
+ if len(results) == 0 {
+ title = "No results"
+ body = "Error: no results"
+ } else {
+ title = fmt.Sprintf("%d results", len(results))
+ for _, result := range results {
+ body += fmt.Sprintf("-----\n%s\n", result)
+ }
+ }
}
- return nil
- })
+ }
+
+ return title, body, shouldSetOrigin
+}
+
+func printResponseBody(g *gocui.Gui, title string, body string, shouldSetOrigin bool) {
+ v, _ := g.View(RESPONSE_BODY_VIEW)
+ v.Clear()
+ v.Title = title
+ fmt.Fprint(v, body)
+
+ if _, err := v.Line(0); shouldSetOrigin || err != nil {
+ v.SetOrigin(0, 0)
+ }
+}
+
+func formatJson(text []byte) []byte {
+ formatter := jsoncolor.NewFormatter()
+ buf := bytes.NewBuffer(make([]byte, 0, len(text)))
+ if err := formatter.Format(buf, text); err == nil {
+ return buf.Bytes()
+ }
+ return text
}
func parseKey(k string) (interface{}, gocui.Modifier, error) {
From f1d7f04165c5c25119af7fca51a521da547e2ff9 Mon Sep 17 00:00:00 2001
From: Pawel Wolowiec
Date: Mon, 20 Feb 2017 21:56:04 +0100
Subject: [PATCH 11/15] Added response info view that displays errors or
response time + further minor refactorings
---
wuzz.go | 162 +++++++++++++++++++++++++++++++-------------------------
1 file changed, 90 insertions(+), 72 deletions(-)
diff --git a/wuzz.go b/wuzz.go
index 460c269..090b25a 100644
--- a/wuzz.go
+++ b/wuzz.go
@@ -42,6 +42,7 @@ const (
REQUEST_DATA_VIEW = "data"
REQUEST_HEADERS_VIEW = "headers"
SEARCH_VIEW = "search"
+ RESPONSE_INFO_VIEW = "response-info"
RESPONSE_HEADERS_VIEW = "response-headers"
RESPONSE_BODY_VIEW = "response-body"
@@ -91,10 +92,15 @@ var VIEW_POSITIONS = map[string]viewPosition{
position{0.5, 1},
position{0.3, 0},
position{1.0, -3}},
- RESPONSE_HEADERS_VIEW: {
+ RESPONSE_INFO_VIEW: {
position{0.3, 0},
position{0.0, 3},
position{1.0, -2},
+ position{0.0, 6}},
+ RESPONSE_HEADERS_VIEW: {
+ position{0.3, 0},
+ position{0.0, 6},
+ position{1.0, -2},
position{0.25, 2}},
RESPONSE_BODY_VIEW: {
position{0.3, 0},
@@ -169,6 +175,13 @@ var VIEW_PROPERTIES = map[string]viewProperties{
wrap: false,
editor: &defaultEditor,
},
+ RESPONSE_INFO_VIEW: {
+ title: "Response info",
+ frame: true,
+ editable: true,
+ wrap: true,
+ editor: nil, // should be set using a.getViewEditor(g)
+ },
RESPONSE_HEADERS_VIEW: {
title: "Response headers",
frame: true,
@@ -254,6 +267,7 @@ var VIEWS = []string{
REQUEST_DATA_VIEW,
REQUEST_HEADERS_VIEW,
SEARCH_VIEW,
+ RESPONSE_INFO_VIEW,
RESPONSE_HEADERS_VIEW,
RESPONSE_BODY_VIEW,
}
@@ -328,10 +342,7 @@ func (e *ViewEditor) Edit(v *gocui.View, key gocui.Key, ch rune, mod gocui.Modif
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 {
- e.wuzzEditor.app.PrintBody(g)
- return nil
- })
+ e.wuzzEditor.app.getAndPrintResponseBody(e.wuzzEditor.g)
}
// The singleLineEditor removes multi lines capabilities
@@ -412,7 +423,7 @@ func (a *App) Layout(g *gocui.Gui) error {
a.setView(g)
}
- for _, name := range []string{RESPONSE_HEADERS_VIEW, RESPONSE_BODY_VIEW} {
+ for _, name := range []string{RESPONSE_INFO_VIEW, RESPONSE_HEADERS_VIEW, RESPONSE_BODY_VIEW} {
vp := VIEW_PROPERTIES[name]
vp.editor = a.getResponseViewEditor(g)
VIEW_PROPERTIES[name] = vp
@@ -428,6 +439,7 @@ func (a *App) Layout(g *gocui.Gui) error {
REQUEST_METHOD_VIEW,
REQUEST_DATA_VIEW,
REQUEST_HEADERS_VIEW,
+ RESPONSE_INFO_VIEW,
RESPONSE_HEADERS_VIEW,
RESPONSE_BODY_VIEW,
SEARCH_PROMPT_VIEW,
@@ -485,7 +497,7 @@ func (a *App) SubmitRequest(g *gocui.Gui, _ *gocui.View) error {
func (a *App) CreateAndProcessRequest(g *gocui.Gui) {
defer func() {
if r := recover(); r != nil {
- displayErrorInResponseBody(g, r)
+ printResponseInfo(g, r)
}
}()
@@ -517,7 +529,7 @@ func (a *App) CreateAndProcessRequest(g *gocui.Gui) {
request := getHttpRequest(r.Method, u, headers, body)
// do request
- response := getHttpResponse(request)
+ response, duration := getHttpResponse(request)
defer response.Body.Close()
// set content type
@@ -545,19 +557,9 @@ func (a *App) CreateAndProcessRequest(g *gocui.Gui) {
a.historyIndex = len(a.history) - 1
// render response
- g.Execute(func(g *gocui.Gui) error {
- printResponseHeaders(g, responseHeaders)
- a.getAndPrintResponseBody(g)
- return nil
- })
-}
-
-func displayErrorInResponseBody(g *gocui.Gui, a interface{}) {
- g.Execute(func(g *gocui.Gui) error {
- v, _ := g.View(RESPONSE_BODY_VIEW)
- fmt.Fprint(v, a)
- return nil
- })
+ printResponseInfo(g, fmt.Sprintf("Response time: %v", duration))
+ printResponseHeaders(g, responseHeaders)
+ a.getAndPrintResponseBody(g)
}
func displayInfo(g *gocui.Gui, msg string) {
@@ -635,12 +637,14 @@ func getHttpRequest(method string, url *url.URL, headers http.Header, body io.Re
return request
}
-func getHttpResponse(request *http.Request) *http.Response {
+func getHttpResponse(request *http.Request) (*http.Response, time.Duration) {
+ start := time.Now()
response, err := CLIENT.Do(request)
+ duration := time.Since(start)
if err != nil {
panic(fmt.Sprintf("Response error: %v", err))
}
- return response
+ return response, duration
}
func getSortedResponseHeaders(response *http.Response) string {
@@ -674,38 +678,45 @@ func statusCodeToColor(code int) int {
}
}
-func printResponseHeaders(g *gocui.Gui, headersString string) {
- v, _ := g.View(RESPONSE_HEADERS_VIEW)
- v.Clear()
- fmt.Fprint(v, headersString)
- if _, err := v.Line(0); err != nil {
+func printResponseInfo(g *gocui.Gui, info interface{}) {
+ g.Execute(func(g *gocui.Gui) error {
+ v, _ := g.View(RESPONSE_INFO_VIEW)
+ v.Clear()
+ fmt.Fprint(v, info)
v.SetOrigin(0, 0)
- }
+ return nil
+ })
}
-func (a *App) PrintBody(g *gocui.Gui) {
+func printResponseHeaders(g *gocui.Gui, headersString string) {
g.Execute(func(g *gocui.Gui) error {
- a.getAndPrintResponseBody(g)
+ v, _ := g.View(RESPONSE_HEADERS_VIEW)
+ v.Clear()
+ fmt.Fprint(v, headersString)
+ if _, err := v.Line(0); err != nil {
+ v.SetOrigin(0, 0)
+ }
return nil
})
}
func (a *App) getAndPrintResponseBody(g *gocui.Gui) {
+ title, body, shouldSetOrigin := a.getResponseBody(g)
+ printResponseBody(g, title, body, shouldSetOrigin)
+}
+
+func (a *App) getResponseBody(g *gocui.Gui) (title, body string, shouldSetOrigin bool) {
if len(a.history) == 0 {
return
}
req := a.history[a.historyIndex]
- if req.RawResponseBody == nil {
- return
- }
- title, body, shouldSetOrigin := getResponseBody(
+ return getResponseBody(
getViewValue(g, SEARCH_VIEW),
req.RawResponseBody,
req.ContentType,
a.config.General,
)
- printResponseBody(g, title, body, shouldSetOrigin)
}
func getResponseBody(
@@ -714,38 +725,41 @@ func getResponseBody(
contentType string,
generalAppOptions config.GeneralOptions) (title, body string, shouldSetOrigin bool) {
- isText := strings.Contains(contentType, "text")
- isApplication := strings.Contains(contentType, "application")
- isJson := strings.Contains(contentType, "application/json")
- isBinary := !(isText || isApplication)
-
title = VIEW_PROPERTIES[RESPONSE_BODY_VIEW].title
- if searchString == "" || isBinary {
- if isBinary {
- title += " [binary content]"
- body = hex.Dump(responseBody)
- } else {
- if isJson && generalAppOptions.FormatJSON {
- responseBody = formatJson(responseBody)
+
+ if responseBody != nil {
+ isText := strings.Contains(contentType, "text")
+ isApplication := strings.Contains(contentType, "application")
+ isJson := strings.Contains(contentType, "application/json")
+ isBinary := !(isText || isApplication)
+
+ if searchString == "" || isBinary {
+ if isBinary {
+ title += " [binary content]"
+ body = hex.Dump(responseBody)
+ } else {
+ if isJson && generalAppOptions.FormatJSON {
+ responseBody = formatJson(responseBody)
+ }
+ body = string(responseBody)
+ }
+ if !generalAppOptions.PreserveScrollPosition {
+ shouldSetOrigin = true
}
- body = string(responseBody)
- }
- if !generalAppOptions.PreserveScrollPosition {
- shouldSetOrigin = true
- }
- } else {
- shouldSetOrigin = true
- if search_re, err := regexp.Compile(searchString); err != nil {
- body = "Error: invalid search regexp"
} else {
- results := search_re.FindAll(responseBody, 1000)
- if len(results) == 0 {
- title = "No results"
- body = "Error: no results"
+ shouldSetOrigin = true
+ if search_re, err := regexp.Compile(searchString); err != nil {
+ body = "Error: invalid search regexp"
} else {
- title = fmt.Sprintf("%d results", len(results))
- for _, result := range results {
- body += fmt.Sprintf("-----\n%s\n", result)
+ results := search_re.FindAll(responseBody, 1000)
+ if len(results) == 0 {
+ title = "No results"
+ body = "Error: no results"
+ } else {
+ title = fmt.Sprintf("%d results", len(results))
+ for _, result := range results {
+ body += fmt.Sprintf("-----\n%s\n", result)
+ }
}
}
}
@@ -755,14 +769,18 @@ func getResponseBody(
}
func printResponseBody(g *gocui.Gui, title string, body string, shouldSetOrigin bool) {
- v, _ := g.View(RESPONSE_BODY_VIEW)
- v.Clear()
- v.Title = title
- fmt.Fprint(v, body)
+ g.Execute(func(g *gocui.Gui) error {
+ v, _ := g.View(RESPONSE_BODY_VIEW)
+ v.Clear()
+ v.Title = title
+ fmt.Fprint(v, body)
- if _, err := v.Line(0); shouldSetOrigin || err != nil {
- v.SetOrigin(0, 0)
- }
+ if _, err := v.Line(0); shouldSetOrigin || err != nil {
+ v.SetOrigin(0, 0)
+ }
+
+ return nil
+ })
}
func formatJson(text []byte) []byte {
@@ -1149,7 +1167,7 @@ func (a *App) restoreRequest(g *gocui.Gui, idx int) {
v, _ = g.View(RESPONSE_HEADERS_VIEW)
setViewTextAndCursor(v, r.ResponseHeaders)
- a.PrintBody(g)
+ a.getAndPrintResponseBody(g)
}
From b73f898f09ee9c1788af77852affbea2f5647b9b Mon Sep 17 00:00:00 2001
From: Pawel Wolowiec
Date: Mon, 20 Feb 2017 23:54:19 +0100
Subject: [PATCH 12/15] Very minor typos fix (so that IDE doesn't bug me about
those)
---
wuzz.go | 22 +++++++++++-----------
1 file changed, 11 insertions(+), 11 deletions(-)
diff --git a/wuzz.go b/wuzz.go
index 090b25a..f1663cb 100644
--- a/wuzz.go
+++ b/wuzz.go
@@ -319,7 +319,7 @@ func init() {
CLIENT.Transport = TRANSPORT
}
-// Editor funcs
+// Editor functions
func (e *ViewEditor) Edit(v *gocui.View, key gocui.Key, ch rune, mod gocui.Modifier) {
// handle back-tab (\033[Z) sequence
@@ -350,7 +350,7 @@ func (e singleLineEditor) Edit(v *gocui.View, key gocui.Key, ch rune, mod gocui.
switch {
case (ch != 0 || key == gocui.KeySpace) && mod == 0:
e.wuzzEditor.Edit(v, key, ch, mod)
- // At the end of the line the default gcui editor adds a whitespace
+ // At the end of the line the default gocui editor adds a whitespace
// Force him to remove
ox, _ := v.Cursor()
if ox > 1 && ox >= len(v.Buffer())-2 {
@@ -480,7 +480,7 @@ func (a *App) setViewByName(g *gocui.Gui, name string) error {
return a.setView(g)
}
}
- return fmt.Errorf("View not found")
+ return errors.New("View not found")
}
func (a *App) SubmitRequest(g *gocui.Gui, _ *gocui.View) error {
@@ -840,7 +840,7 @@ func (a *App) setKey(g *gocui.Gui, keyStr, commandStr, viewName string) error {
return nil
}
-func (a *App) printViewKeybindings(v io.Writer, viewName string) {
+func (a *App) printViewKeyBindings(v io.Writer, viewName string) {
keys, found := a.config.Keys[viewName]
if !found {
return
@@ -859,7 +859,7 @@ func (a *App) printViewKeybindings(v io.Writer, viewName string) {
}
func (a *App) SetKeys(g *gocui.Gui) error {
- // load config keybindings
+ // load config key bindings
for viewName, keys := range a.config.Keys {
if viewName == "global" {
viewName = ALL_VIEWS
@@ -884,12 +884,12 @@ func (a *App) SetKeys(g *gocui.Gui) error {
help.Title = VIEW_PROPERTIES[HELP_VIEW].title
help.Highlight = false
fmt.Fprint(help, "Keybindings:\n")
- a.printViewKeybindings(help, "global")
+ a.printViewKeyBindings(help, "global")
for _, viewName := range VIEWS {
if _, found := a.config.Keys[viewName]; !found {
continue
}
- a.printViewKeybindings(help, viewName)
+ a.printViewKeyBindings(help, viewName)
}
g.SetViewOnTop(HELP_VIEW)
g.SetCurrentView(HELP_VIEW)
@@ -1010,11 +1010,11 @@ func (a *App) SetKeys(g *gocui.Gui) error {
return nil
}
-func (a *App) closePopup(g *gocui.Gui, viewname string) {
- _, err := g.View(viewname)
+func (a *App) closePopup(g *gocui.Gui, viewName string) {
+ _, err := g.View(viewName)
if err == nil {
a.currentPopup = ""
- g.DeleteView(viewname)
+ g.DeleteView(viewName)
g.SetCurrentView(VIEWS[a.viewIndex%len(VIEWS)])
g.Cursor = true
}
@@ -1258,7 +1258,7 @@ func (a *App) ParseArgs(g *gocui.Gui, args []string) error {
if err != nil || timeout <= 0 {
return errors.New("Invalid timeout value")
}
- a.config.General.Timeout = config.Duration{time.Duration(timeout) * time.Millisecond}
+ a.config.General.Timeout = config.Duration{Duration: time.Duration(timeout) * time.Millisecond}
case "--compressed":
vh, _ := g.View(REQUEST_HEADERS_VIEW)
if strings.Index(getViewValue(g, REQUEST_HEADERS_VIEW), "Accept-Encoding") == -1 {
From fa7124ce2f714f931156378aa17960b422daeb05 Mon Sep 17 00:00:00 2001
From: Pawel Wolowiec
Date: Tue, 21 Feb 2017 04:14:14 +0100
Subject: [PATCH 13/15] Refactored editors + taken care of issue "Home/End
doesn't work in other areas except URL #69"
---
wuzz.go | 174 ++++++++++++++++++++++++++++++++------------------------
1 file changed, 99 insertions(+), 75 deletions(-)
diff --git a/wuzz.go b/wuzz.go
index f1663cb..f62184f 100644
--- a/wuzz.go
+++ b/wuzz.go
@@ -134,7 +134,7 @@ type viewProperties struct {
frame bool
editable bool
wrap bool
- editor gocui.Editor
+ editor *gocui.Editor
text string
}
@@ -144,7 +144,7 @@ var VIEW_PROPERTIES = map[string]viewProperties{
frame: true,
editable: true,
wrap: false,
- editor: &singleLineEditor{&defaultEditor},
+ editor: &singleLineEditor,
},
URL_PARAMS_VIEW: {
title: "URL params",
@@ -158,7 +158,7 @@ var VIEW_PROPERTIES = map[string]viewProperties{
frame: true,
editable: true,
wrap: false,
- editor: &singleLineEditor{&defaultEditor},
+ editor: &singleLineEditor,
text: DEFAULT_METHOD,
},
REQUEST_DATA_VIEW: {
@@ -180,35 +180,34 @@ var VIEW_PROPERTIES = map[string]viewProperties{
frame: true,
editable: true,
wrap: true,
- editor: nil, // should be set using a.getViewEditor(g)
+ editor: &emptyEditor,
},
RESPONSE_HEADERS_VIEW: {
title: "Response headers",
frame: true,
editable: true,
wrap: true,
- editor: nil, // should be set using a.getViewEditor(g)
+ editor: &emptyEditor,
},
RESPONSE_BODY_VIEW: {
title: "Response body",
frame: true,
editable: true,
wrap: true,
- editor: nil, // should be set using a.getViewEditor(g)
+ editor: &emptyEditor,
},
SEARCH_VIEW: {
title: "",
frame: false,
editable: true,
wrap: false,
- editor: &singleLineEditor{&SearchEditor{&defaultEditor}},
+ editor: &searchEditor,
},
SEARCH_PROMPT_VIEW: {
title: "",
frame: false,
editable: false,
wrap: false,
- editor: nil,
text: SEARCH_PROMPT,
},
ERROR_VIEW: {
@@ -216,14 +215,12 @@ var VIEW_PROPERTIES = map[string]viewProperties{
frame: true,
editable: false,
wrap: false,
- editor: nil,
},
POPUP_VIEW: {
title: "Info",
frame: true,
editable: false,
wrap: false,
- editor: nil,
},
HISTORY_VIEW: {
title: "History",
@@ -272,8 +269,6 @@ var VIEWS = []string{
RESPONSE_BODY_VIEW,
}
-var defaultEditor ViewEditor
-
const (
MIN_WIDTH = 60
MIN_HEIGHT = 20
@@ -298,88 +293,126 @@ type App struct {
config *config.Config
}
-type ViewEditor struct {
- app *App
- g *gocui.Gui
- backTabEscape bool
- origEditor gocui.Editor
+// Acts as an editor but does nothing
+type EmptyEditor struct {
+ // (!) Deliberately left empty
}
-type SearchEditor struct {
- wuzzEditor *ViewEditor
+func (e EmptyEditor) Edit(v *gocui.View, key gocui.Key, ch rune, mod gocui.Modifier) {
+ // (!) Deliberately left empty
}
-// The singleLineEditor removes multi lines capabilities
-type singleLineEditor struct {
- wuzzEditor gocui.Editor
+// Handles BackTab (\033[Z) sequence
+type BackTabEditor struct {
+ editor gocui.Editor
+ goBack func()
+ waitingForSecondBackTabRune bool
}
-func init() {
- TRANSPORT.DisableCompression = true
- CLIENT.Transport = TRANSPORT
-}
-
-// Editor functions
-
-func (e *ViewEditor) Edit(v *gocui.View, key gocui.Key, ch rune, mod gocui.Modifier) {
- // handle back-tab (\033[Z) sequence
- if e.backTabEscape {
+func (e *BackTabEditor) Edit(v *gocui.View, key gocui.Key, ch rune, mod gocui.Modifier) {
+ if e.waitingForSecondBackTabRune {
if ch == 'Z' {
- e.app.PrevView(e.g, nil)
- e.backTabEscape = false
+ e.goBack()
+ e.waitingForSecondBackTabRune = false
return
} else {
- e.origEditor.Edit(v, 0, '[', gocui.ModAlt)
+ e.editor.Edit(v, 0, '[', gocui.ModAlt)
}
}
+
if ch == '[' && mod == gocui.ModAlt {
- e.backTabEscape = true
- return
+ e.waitingForSecondBackTabRune = true
+ } else {
+ e.editor.Edit(v, key, ch, mod)
}
+}
- e.origEditor.Edit(v, key, ch, mod)
+// Calls search function
+type SearchEditor struct {
+ editor gocui.Editor
+ search func()
+}
+
+func (e SearchEditor) Edit(v *gocui.View, key gocui.Key, ch rune, mod gocui.Modifier) {
+ e.editor.Edit(v, key, ch, mod)
+ e.search()
+}
+
+// Adds home and end buttons functionality
+type HomeEndEditor struct {
+ editor gocui.Editor
+}
+
+func (e HomeEndEditor) Edit(v *gocui.View, key gocui.Key, ch rune, mod gocui.Modifier) {
+ switch key {
+ case gocui.KeyHome:
+ v.SetCursor(0, 0)
+ case gocui.KeyEnd:
+ v.SetCursor(len(v.Buffer())-1, 0)
+ default:
+ e.editor.Edit(v, key, ch, mod)
+ }
}
-func (e *SearchEditor) Edit(v *gocui.View, key gocui.Key, ch rune, mod gocui.Modifier) {
- e.wuzzEditor.Edit(v, key, ch, mod)
- e.wuzzEditor.app.getAndPrintResponseBody(e.wuzzEditor.g)
+// Removes multi lines capabilities
+type SingleLineEditor struct {
+ editor gocui.Editor
}
-// The singleLineEditor removes multi lines capabilities
-func (e singleLineEditor) Edit(v *gocui.View, key gocui.Key, ch rune, mod gocui.Modifier) {
+func (e SingleLineEditor) Edit(v *gocui.View, key gocui.Key, ch rune, mod gocui.Modifier) {
switch {
case (ch != 0 || key == gocui.KeySpace) && mod == 0:
- e.wuzzEditor.Edit(v, key, ch, mod)
+ e.editor.Edit(v, key, ch, mod)
// At the end of the line the default gocui editor adds a whitespace
// Force him to remove
- ox, _ := v.Cursor()
- if ox > 1 && ox >= len(v.Buffer())-2 {
+ o, _ := v.Cursor()
+ if o > 1 && o >= len(v.Buffer())-2 {
v.EditDelete(false)
}
return
+ case key == gocui.KeyArrowUp:
+ key = gocui.KeyHome
+ case key == gocui.KeyArrowDown:
+ key = gocui.KeyEnd
case key == gocui.KeyEnter:
return
case key == gocui.KeyArrowRight:
- ox, _ := v.Cursor()
- if ox >= len(v.Buffer())-1 {
+ if x, _ := v.Cursor(); x > len(v.Buffer()) {
return
}
- case key == gocui.KeyHome || key == gocui.KeyArrowUp:
- v.SetCursor(0, 0)
- return
- case key == gocui.KeyEnd || key == gocui.KeyArrowDown:
- v.SetCursor(len(v.Buffer())-1, 0)
- return
}
- e.wuzzEditor.Edit(v, key, ch, mod)
+
+ e.editor.Edit(v, key, ch, mod)
}
-//
+var defaultEditor, singleLineEditor, searchEditor, emptyEditor gocui.Editor
-func (a *App) getResponseViewEditor(g *gocui.Gui) gocui.Editor {
- return &ViewEditor{a, g, false, gocui.EditorFunc(func(v *gocui.View, key gocui.Key, ch rune, mod gocui.Modifier) {
- return
- })}
+func (a *App) getPrevViewFunc(g *gocui.Gui) func() {
+ return func() {
+ a.PrevView(g, nil)
+ }
+}
+
+func (a *App) getSearchFun(g *gocui.Gui) func() {
+ return func() {
+ a.getAndPrintResponseBody(g)
+ }
+}
+
+func (a *App) initiateEditors(g *gocui.Gui) {
+ defaultEditor = &BackTabEditor{
+ HomeEndEditor{gocui.DefaultEditor},
+ a.getPrevViewFunc(g),
+ false}
+ singleLineEditor = SingleLineEditor{
+ defaultEditor}
+ searchEditor = SearchEditor{
+ singleLineEditor,
+ a.getSearchFun(g)}
+ emptyEditor = &BackTabEditor{
+ EmptyEditor{},
+ a.getPrevViewFunc(g),
+ false}
}
func (p position) getCoordinate(max int) int {
@@ -401,7 +434,9 @@ func setViewProperties(v *gocui.View, name string) {
v.Frame = VIEW_PROPERTIES[name].frame
v.Editable = VIEW_PROPERTIES[name].editable
v.Wrap = VIEW_PROPERTIES[name].wrap
- v.Editor = VIEW_PROPERTIES[name].editor
+ if VIEW_PROPERTIES[name].editor != nil {
+ v.Editor = *VIEW_PROPERTIES[name].editor
+ }
setViewTextAndCursor(v, VIEW_PROPERTIES[name].text)
}
@@ -423,12 +458,6 @@ func (a *App) Layout(g *gocui.Gui) error {
a.setView(g)
}
- for _, name := range []string{RESPONSE_INFO_VIEW, RESPONSE_HEADERS_VIEW, RESPONSE_BODY_VIEW} {
- vp := VIEW_PROPERTIES[name]
- vp.editor = a.getResponseViewEditor(g)
- VIEW_PROPERTIES[name] = vp
- }
-
p := VIEW_PROPERTIES[URL_VIEW]
p.text = a.config.General.DefaultURLScheme + "://"
VIEW_PROPERTIES[URL_VIEW] = p
@@ -701,22 +730,18 @@ func printResponseHeaders(g *gocui.Gui, headersString string) {
}
func (a *App) getAndPrintResponseBody(g *gocui.Gui) {
- title, body, shouldSetOrigin := a.getResponseBody(g)
- printResponseBody(g, title, body, shouldSetOrigin)
-}
-
-func (a *App) getResponseBody(g *gocui.Gui) (title, body string, shouldSetOrigin bool) {
if len(a.history) == 0 {
return
}
req := a.history[a.historyIndex]
- return getResponseBody(
+ title, body, shouldSetOrigin := getResponseBody(
getViewValue(g, SEARCH_VIEW),
req.RawResponseBody,
req.ContentType,
a.config.General,
)
+ printResponseBody(g, title, body, shouldSetOrigin)
}
func getResponseBody(
@@ -1379,8 +1404,7 @@ func main() {
app := &App{history: make([]*Request, 0, 31)}
- // overwrite default editor
- defaultEditor = ViewEditor{app, g, false, gocui.DefaultEditor}
+ app.initiateEditors(g)
initApp(app, g)
From d075c00e0e6d2a4eaa6c9419c31a9395a69edd8e Mon Sep 17 00:00:00 2001
From: Pawel Wolowiec
Date: Tue, 21 Feb 2017 04:21:20 +0100
Subject: [PATCH 14/15] Moved editors to separate file
---
editors.go | 97 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
wuzz.go | 92 ---------------------------------------------------
2 files changed, 97 insertions(+), 92 deletions(-)
create mode 100644 editors.go
diff --git a/editors.go b/editors.go
new file mode 100644
index 0000000..5610454
--- /dev/null
+++ b/editors.go
@@ -0,0 +1,97 @@
+package main
+
+import (
+ "github.com/jroimartin/gocui"
+)
+
+// Acts as an editor but does nothing
+type EmptyEditor struct {
+ // (!) Deliberately left empty
+}
+
+func (e EmptyEditor) Edit(v *gocui.View, key gocui.Key, ch rune, mod gocui.Modifier) {
+ // (!) Deliberately left empty
+}
+
+// Handles BackTab (\033[Z) sequence
+type BackTabEditor struct {
+ editor gocui.Editor
+ goBack func()
+ waitingForSecondBackTabRune bool
+}
+
+func (e *BackTabEditor) Edit(v *gocui.View, key gocui.Key, ch rune, mod gocui.Modifier) {
+ if e.waitingForSecondBackTabRune {
+ if ch == 'Z' {
+ e.goBack()
+ e.waitingForSecondBackTabRune = false
+ return
+ } else {
+ e.editor.Edit(v, 0, '[', gocui.ModAlt)
+ }
+ }
+
+ if ch == '[' && mod == gocui.ModAlt {
+ e.waitingForSecondBackTabRune = true
+ } else {
+ e.editor.Edit(v, key, ch, mod)
+ }
+}
+
+// Calls search function
+type SearchEditor struct {
+ editor gocui.Editor
+ search func()
+}
+
+func (e SearchEditor) Edit(v *gocui.View, key gocui.Key, ch rune, mod gocui.Modifier) {
+ e.editor.Edit(v, key, ch, mod)
+ e.search()
+}
+
+// Adds home and end buttons functionality
+type HomeEndEditor struct {
+ editor gocui.Editor
+}
+
+func (e HomeEndEditor) Edit(v *gocui.View, key gocui.Key, ch rune, mod gocui.Modifier) {
+ switch key {
+ case gocui.KeyHome:
+ v.SetCursor(0, 0)
+ case gocui.KeyEnd:
+ v.SetCursor(len(v.Buffer())-1, 0)
+ default:
+ e.editor.Edit(v, key, ch, mod)
+ }
+}
+
+// Removes multi lines capabilities
+type SingleLineEditor struct {
+ editor gocui.Editor
+}
+
+func (e SingleLineEditor) Edit(v *gocui.View, key gocui.Key, ch rune, mod gocui.Modifier) {
+ switch {
+ case (ch != 0 || key == gocui.KeySpace) && mod == 0:
+ e.editor.Edit(v, key, ch, mod)
+ // At the end of the line the default gocui editor adds a whitespace
+ // Force him to remove
+ o, _ := v.Cursor()
+ if o > 1 && o >= len(v.Buffer())-2 {
+ v.EditDelete(false)
+ }
+ return
+ case key == gocui.KeyArrowUp:
+ key = gocui.KeyHome
+ case key == gocui.KeyArrowDown:
+ key = gocui.KeyEnd
+ case key == gocui.KeyEnter:
+ return
+ case key == gocui.KeyArrowRight:
+ if x, _ := v.Cursor(); x > len(v.Buffer()) {
+ return
+ }
+ }
+
+ e.editor.Edit(v, key, ch, mod)
+}
diff --git a/wuzz.go b/wuzz.go
index f62184f..30b9cf2 100644
--- a/wuzz.go
+++ b/wuzz.go
@@ -293,98 +293,6 @@ type App struct {
config *config.Config
}
-// Acts as an editor but does nothing
-type EmptyEditor struct {
- // (!) Deliberately left empty
-}
-
-func (e EmptyEditor) Edit(v *gocui.View, key gocui.Key, ch rune, mod gocui.Modifier) {
- // (!) Deliberately left empty
-}
-
-// Handles BackTab (\033[Z) sequence
-type BackTabEditor struct {
- editor gocui.Editor
- goBack func()
- waitingForSecondBackTabRune bool
-}
-
-func (e *BackTabEditor) Edit(v *gocui.View, key gocui.Key, ch rune, mod gocui.Modifier) {
- if e.waitingForSecondBackTabRune {
- if ch == 'Z' {
- e.goBack()
- e.waitingForSecondBackTabRune = false
- return
- } else {
- e.editor.Edit(v, 0, '[', gocui.ModAlt)
- }
- }
-
- if ch == '[' && mod == gocui.ModAlt {
- e.waitingForSecondBackTabRune = true
- } else {
- e.editor.Edit(v, key, ch, mod)
- }
-}
-
-// Calls search function
-type SearchEditor struct {
- editor gocui.Editor
- search func()
-}
-
-func (e SearchEditor) Edit(v *gocui.View, key gocui.Key, ch rune, mod gocui.Modifier) {
- e.editor.Edit(v, key, ch, mod)
- e.search()
-}
-
-// Adds home and end buttons functionality
-type HomeEndEditor struct {
- editor gocui.Editor
-}
-
-func (e HomeEndEditor) Edit(v *gocui.View, key gocui.Key, ch rune, mod gocui.Modifier) {
- switch key {
- case gocui.KeyHome:
- v.SetCursor(0, 0)
- case gocui.KeyEnd:
- v.SetCursor(len(v.Buffer())-1, 0)
- default:
- e.editor.Edit(v, key, ch, mod)
- }
-}
-
-// Removes multi lines capabilities
-type SingleLineEditor struct {
- editor gocui.Editor
-}
-
-func (e SingleLineEditor) Edit(v *gocui.View, key gocui.Key, ch rune, mod gocui.Modifier) {
- switch {
- case (ch != 0 || key == gocui.KeySpace) && mod == 0:
- e.editor.Edit(v, key, ch, mod)
- // At the end of the line the default gocui editor adds a whitespace
- // Force him to remove
- o, _ := v.Cursor()
- if o > 1 && o >= len(v.Buffer())-2 {
- v.EditDelete(false)
- }
- return
- case key == gocui.KeyArrowUp:
- key = gocui.KeyHome
- case key == gocui.KeyArrowDown:
- key = gocui.KeyEnd
- case key == gocui.KeyEnter:
- return
- case key == gocui.KeyArrowRight:
- if x, _ := v.Cursor(); x > len(v.Buffer()) {
- return
- }
- }
-
- e.editor.Edit(v, key, ch, mod)
-}
-
var defaultEditor, singleLineEditor, searchEditor, emptyEditor gocui.Editor
func (a *App) getPrevViewFunc(g *gocui.Gui) func() {
From 0cf3fd9d3ee6fc2a4f3c719e92a6a454aa450253 Mon Sep 17 00:00:00 2001
From: Pawel Wolowiec
Date: Tue, 21 Feb 2017 05:23:16 +0100
Subject: [PATCH 15/15] Various minor refactorings + moved help text to
separate file
---
config/helpText.go | 19 ++++
editors.go | 4 +-
wuzz.go | 219 +++++++++++++++++++++------------------------
3 files changed, 125 insertions(+), 117 deletions(-)
create mode 100644 config/helpText.go
diff --git a/config/helpText.go b/config/helpText.go
new file mode 100644
index 0000000..b78b0e1
--- /dev/null
+++ b/config/helpText.go
@@ -0,0 +1,19 @@
+package config
+
+var HelpText = `wuzz - Interactive cli tool for HTTP inspection
+
+Usage: wuzz [-H|--header HEADER]... [-d|--data|--data-binary DATA] [-X|--request METHOD] [-t|--timeout MSECS] [URL]
+
+Other command line options:
+ -c, --config PATH Specify custom configuration file
+ -h, --help Show this
+ -v, --version Display version number
+
+Key bindings:
+ ctrl+r Send request
+ ctrl+s Save response
+ tab, ctrl+j Next window
+ shift+tab, ctrl+k Previous window
+ ctrl+h, alt+h Show history
+ pageUp Scroll up the current window
+ pageDown Scroll down the current window`
diff --git a/editors.go b/editors.go
index 5610454..ffd0332 100644
--- a/editors.go
+++ b/editors.go
@@ -6,11 +6,11 @@ import (
// Acts as an editor but does nothing
type EmptyEditor struct {
- // (!) Deliberately left empty
+ // Deliberately left empty
}
func (e EmptyEditor) Edit(v *gocui.View, key gocui.Key, ch rune, mod gocui.Modifier) {
- // (!) Deliberately left empty
+ // Deliberately left empty
}
// Handles BackTab (\033[Z) sequence
diff --git a/wuzz.go b/wuzz.go
index 30b9cf2..6f2d69f 100644
--- a/wuzz.go
+++ b/wuzz.go
@@ -293,6 +293,8 @@ type App struct {
config *config.Config
}
+// EDITORS
+
var defaultEditor, singleLineEditor, searchEditor, emptyEditor gocui.Editor
func (a *App) getPrevViewFunc(g *gocui.Gui) func() {
@@ -323,6 +325,8 @@ func (a *App) initiateEditors(g *gocui.Gui) {
false}
}
+// VIEW POSITIONS AND PROPERTIES
+
func (p position) getCoordinate(max int) int {
return int(p.pct*float32(max)) + p.abs
}
@@ -348,6 +352,8 @@ func setViewProperties(v *gocui.View, name string) {
setViewTextAndCursor(v, VIEW_PROPERTIES[name].text)
}
+// LAYOUT
+
func (a *App) Layout(g *gocui.Gui) error {
if maxX, maxY := g.Size(); maxX < MIN_WIDTH || maxY < MIN_HEIGHT {
if v, err := setView(g, ERROR_VIEW); err != nil {
@@ -382,10 +388,11 @@ func (a *App) Layout(g *gocui.Gui) error {
SEARCH_PROMPT_VIEW,
SEARCH_VIEW,
} {
- if v, err := setView(g, name); err != nil {
- if err != gocui.ErrUnknownView {
- return err
- }
+ if v, err := setView(g, name); err == nil {
+ // Deliberately left empty
+ } else if err != gocui.ErrUnknownView {
+ return err
+ } else {
setViewProperties(v, name)
}
}
@@ -394,6 +401,8 @@ func (a *App) Layout(g *gocui.Gui) error {
return nil
}
+// VIEW FUNCTIONS
+
func (a *App) NextView(g *gocui.Gui, v *gocui.View) error {
a.viewIndex = (a.viewIndex + 1) % len(VIEWS)
return a.setView(g)
@@ -420,25 +429,31 @@ func (a *App) setViewByName(g *gocui.Gui, name string) error {
return errors.New("View not found")
}
+// REQUEST
+
func (a *App) SubmitRequest(g *gocui.Gui, _ *gocui.View) error {
- rhv, _ := g.View(RESPONSE_HEADERS_VIEW)
- rhv.Clear()
- rbv, _ := g.View(RESPONSE_BODY_VIEW)
- rbv.Clear()
+ for _, name := range []string{
+ RESPONSE_INFO_VIEW,
+ RESPONSE_HEADERS_VIEW,
+ RESPONSE_BODY_VIEW,
+ } {
+ v, _ := g.View(name)
+ v.Clear()
+ }
- go a.CreateAndProcessRequest(g)
+ go a.createAndProcessRequest(g)
return nil
}
-func (a *App) CreateAndProcessRequest(g *gocui.Gui) {
+func (a *App) createAndProcessRequest(g *gocui.Gui) {
defer func() {
if r := recover(); r != nil {
printResponseInfo(g, r)
}
}()
- displayInfo(g, "Sending request..")
+ a.displayRequestInfo(g)
defer g.DeleteView(POPUP_VIEW)
var r *Request = &Request{}
@@ -499,23 +514,11 @@ func (a *App) CreateAndProcessRequest(g *gocui.Gui) {
a.getAndPrintResponseBody(g)
}
-func displayInfo(g *gocui.Gui, msg string) {
- pos := VIEW_POSITIONS[POPUP_VIEW]
- pos.x0.abs = -len(msg)/2 - 1
- pos.x1.abs = len(msg)/2 + 1
- VIEW_POSITIONS[POPUP_VIEW] = pos
-
- p := VIEW_PROPERTIES[POPUP_VIEW]
- p.text = msg
- VIEW_PROPERTIES[POPUP_VIEW] = p
-
- if v, err := setView(g, POPUP_VIEW); err != nil {
- if err != gocui.ErrUnknownView {
- return
- }
- setViewProperties(v, POPUP_VIEW)
- g.SetViewOnTop(POPUP_VIEW)
- }
+func (a *App) displayRequestInfo(g *gocui.Gui) {
+ msg := "Sending request..."
+ v, _ := a.CreatePopupView(POPUP_VIEW, len(msg)+2, 1, g)
+ v.Title = VIEW_PROPERTIES[POPUP_VIEW].title
+ fmt.Fprintln(v, msg)
}
func getUrlFromString(urlString string) *url.URL {
@@ -725,71 +728,7 @@ func formatJson(text []byte) []byte {
return text
}
-func parseKey(k string) (interface{}, gocui.Modifier, error) {
- mod := gocui.ModNone
- if strings.Index(k, "Alt") == 0 {
- mod = gocui.ModAlt
- k = k[3:]
- }
- switch len(k) {
- case 0:
- return 0, 0, errors.New("Empty key string")
- case 1:
- if mod != gocui.ModNone {
- k = strings.ToLower(k)
- }
- return rune(k[0]), mod, nil
- }
-
- key, found := KEYS[k]
- if !found {
- return 0, 0, fmt.Errorf("Unknown key: %v", k)
- }
- return key, mod, nil
-}
-
-func (a *App) setKey(g *gocui.Gui, keyStr, commandStr, viewName string) error {
- if commandStr == "" {
- return nil
- }
- key, mod, err := parseKey(keyStr)
- if err != nil {
- return err
- }
- commandParts := strings.SplitN(commandStr, " ", 2)
- command := commandParts[0]
- var commandArgs string
- if len(commandParts) == 2 {
- commandArgs = commandParts[1]
- }
- keyFnGen, found := COMMANDS[command]
- if !found {
- return fmt.Errorf("Unknown command: %v", command)
- }
- keyFn := keyFnGen(commandArgs, a)
- if err := g.SetKeybinding(viewName, key, mod, keyFn); err != nil {
- return fmt.Errorf("Failed to set key '%v': %v", keyStr, err)
- }
- return nil
-}
-
-func (a *App) printViewKeyBindings(v io.Writer, viewName string) {
- keys, found := a.config.Keys[viewName]
- if !found {
- return
- }
- mk := make([]string, len(keys))
- i := 0
- for k := range keys {
- mk[i] = k
- i++
- }
- sort.Strings(mk)
- fmt.Fprintf(v, "\n %v\n", viewName)
- for _, key := range mk {
- fmt.Fprintf(v, " %-15v %v\n", key, keys[key])
- }
-}
+// KEY BINDINGS
func (a *App) SetKeys(g *gocui.Gui) error {
// load config key bindings
@@ -943,6 +882,74 @@ func (a *App) SetKeys(g *gocui.Gui) error {
return nil
}
+func (a *App) setKey(g *gocui.Gui, keyStr, commandStr, viewName string) error {
+ if commandStr == "" {
+ return nil
+ }
+ key, mod, err := parseKey(keyStr)
+ if err != nil {
+ return err
+ }
+ commandParts := strings.SplitN(commandStr, " ", 2)
+ command := commandParts[0]
+ var commandArgs string
+ if len(commandParts) == 2 {
+ commandArgs = commandParts[1]
+ }
+ keyFnGen, found := COMMANDS[command]
+ if !found {
+ return fmt.Errorf("Unknown command: %v", command)
+ }
+ keyFn := keyFnGen(commandArgs, a)
+ if err := g.SetKeybinding(viewName, key, mod, keyFn); err != nil {
+ return fmt.Errorf("Failed to set key '%v': %v", keyStr, err)
+ }
+ return nil
+}
+
+func parseKey(k string) (interface{}, gocui.Modifier, error) {
+ mod := gocui.ModNone
+ if strings.Index(k, "Alt") == 0 {
+ mod = gocui.ModAlt
+ k = k[3:]
+ }
+ switch len(k) {
+ case 0:
+ return 0, 0, errors.New("Empty key string")
+ case 1:
+ if mod != gocui.ModNone {
+ k = strings.ToLower(k)
+ }
+ return rune(k[0]), mod, nil
+ }
+
+ key, found := KEYS[k]
+ if !found {
+ return 0, 0, fmt.Errorf("Unknown key: %v", k)
+ }
+ return key, mod, nil
+}
+
+func (a *App) printViewKeyBindings(v io.Writer, viewName string) {
+ keys, found := a.config.Keys[viewName]
+ if !found {
+ return
+ }
+ mk := make([]string, len(keys))
+ i := 0
+ for k := range keys {
+ mk[i] = k
+ i++
+ }
+ sort.Strings(mk)
+ fmt.Fprintf(v, "\n %v\n", viewName)
+ for _, key := range mk {
+ fmt.Fprintf(v, " %-15v %v\n", key, keys[key])
+ }
+}
+
+// POPUP VIEWS
+
func (a *App) closePopup(g *gocui.Gui, viewName string) {
_, err := g.View(viewName)
if err == nil {
@@ -953,7 +960,6 @@ func (a *App) closePopup(g *gocui.Gui, viewName string) {
}
}
-// CreatePopupView create a popup like view
func (a *App) CreatePopupView(name string, width, height int, g *gocui.Gui) (v *gocui.View, err error) {
// Remove any concurrent popup
a.closePopup(g, a.currentPopup)
@@ -1104,6 +1110,8 @@ func (a *App) restoreRequest(g *gocui.Gui, idx int) {
}
+// INITIALIZATION
+
func (a *App) LoadConfig(configPath string) error {
if configPath == "" {
// Load config from default path
@@ -1262,26 +1270,7 @@ func setViewTextAndCursor(v *gocui.View, s string) {
v.SetCursor(len(s), 0)
}
-func help() {
- fmt.Println(`wuzz - Interactive cli tool for HTTP inspection
-
-Usage: wuzz [-H|--header HEADER]... [-d|--data|--data-binary DATA] [-X|--request METHOD] [-t|--timeout MSECS] [URL]
-
-Other command line options:
- -c, --config PATH Specify custom configuration file
- -h, --help Show this
- -v, --version Display version number
-
-Key bindings:
- ctrl+r Send request
- ctrl+s Save response
- tab, ctrl+j Next window
- shift+tab, ctrl+k Previous window
- ctrl+h, alt+h Show history
- pageUp Scroll up the current window
- pageDown Scroll down the current window`,
- )
-}
+// MAIN
func main() {
configPath := ""
@@ -1289,7 +1278,7 @@ func main() {
for i, arg := range os.Args {
switch arg {
case "-h", "--help":
- help()
+ fmt.Println(config.HelpText)
return
case "-v", "--version":
fmt.Printf("wuzz %v\n", VERSION)