Skip to content

Commit

Permalink
feat: create main funcionality
Browse files Browse the repository at this point in the history
  • Loading branch information
NathanFirmo committed Sep 28, 2023
1 parent 81396e6 commit 28c3796
Show file tree
Hide file tree
Showing 18 changed files with 463 additions and 2 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,6 @@

# Go workspace file
go.work

# SQLite DBs
*.db
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
# gorest
🗿Terminal rest client like Postman and Insomnia
# Terminal rest client like Postman and Insomnia

14 changes: 14 additions & 0 deletions cmd/gorest/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package main

import (
"github.com/NathanFirmo/gorest/internal/gorest"
_ "github.com/mattn/go-sqlite3"
)

func main() {
app := gorest.CreateApp()

if err := app.Start(); err != nil {
panic(err)
}
}
19 changes: 19 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
module github.com/NathanFirmo/gorest

go 1.21.0

require (
github.com/gdamore/tcell/v2 v2.6.0
github.com/mattn/go-sqlite3 v1.14.17
github.com/rivo/tview v0.0.0-20230814110005-ccc2c8119703
)

require (
github.com/gdamore/encoding v1.0.0 // indirect
github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
github.com/mattn/go-runewidth v0.0.14 // indirect
github.com/rivo/uniseg v0.4.3 // indirect
golang.org/x/sys v0.12.0 // indirect
golang.org/x/term v0.5.0 // indirect
golang.org/x/text v0.7.0 // indirect
)
45 changes: 45 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
github.com/gdamore/encoding v1.0.0 h1:+7OoQ1Bc6eTm5niUzBa0Ctsh6JbMW6Ra+YNuAtDBdko=
github.com/gdamore/encoding v1.0.0/go.mod h1:alR0ol34c49FCSBLjhosxzcPHQbf2trDkoo5dl+VrEg=
github.com/gdamore/tcell/v2 v2.6.0 h1:OKbluoP9VYmJwZwq/iLb4BxwKcwGthaa1YNBJIyCySg=
github.com/gdamore/tcell/v2 v2.6.0/go.mod h1:be9omFATkdr0D9qewWW3d+MEvl5dha+Etb5y65J2H8Y=
github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY=
github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
github.com/mattn/go-runewidth v0.0.14 h1:+xnbZSEeDbOIg5/mE6JF0w6n9duR1l3/WmbinWVwUuU=
github.com/mattn/go-runewidth v0.0.14/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
github.com/mattn/go-sqlite3 v1.14.17 h1:mCRHCLDUBXgpKAqIKsaAaAsrAlbkeomtRFKXh2L6YIM=
github.com/mattn/go-sqlite3 v1.14.17/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg=
github.com/rivo/tview v0.0.0-20230814110005-ccc2c8119703 h1:ZyM/+FYnpbZsFWuCohniM56kRoHRB4r5EuIzXEYkpxo=
github.com/rivo/tview v0.0.0-20230814110005-ccc2c8119703/go.mod h1:nVwGv4MP47T0jvlk7KuTTjjuSmrGO4JF0iaiNt4bufE=
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/rivo/uniseg v0.4.3 h1:utMvzDsuh3suAEnhH0RdHmoPbU648o6CvXxTx4SBMOw=
github.com/rivo/uniseg v0.4.3/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o=
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.5.0 h1:n2a8QNdAb0sZNpU9R1ALUXBbY+w51fCQDN+7EdxNBsY=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.7.0 h1:4BRB4x83lYWy72KwLD/qYDuTu7q9PjSagHvijDw7cLo=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
12 changes: 12 additions & 0 deletions internal/components/request-options-input.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package components

import "github.com/rivo/tview"

// Create a component for request options input
func CreateRequestOptionsInput() *tview.TextArea {
c := tview.NewTextArea()
c.SetBorder(true)
c.SetText("", true)

return c
}
15 changes: 15 additions & 0 deletions internal/components/request-url-input.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package components

import (
"github.com/gdamore/tcell/v2"
"github.com/rivo/tview"
)

// Create a component for url input
func CreateUrlInput() *tview.InputField {
c := tview.NewInputField()
c.SetBorder(true)
c.SetFieldTextColor(tcell.Color(tcell.Color.Hex(0)))

return c
}
35 changes: 35 additions & 0 deletions internal/components/requests-list.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package components

import (
"github.com/rivo/tview"
)

type Request struct {
Url string
Name string
Method string
Headers string
Body string
}

type RequestsListComponent struct {
Items []Request
Component *tview.List
}

// AddItem a new request into requests list
func (rl *RequestsListComponent) AddItem(r *Request, cb func()) {
rl.Component.AddItem(r.Name, r.Url, 0, cb)

rl.Items = append(rl.Items, *r)
}

// Create a component to show requests list
func CreateRequestsList() *RequestsListComponent {
c := tview.NewList()

return &RequestsListComponent{
Component: c,
Items: make([]Request, 0),
}
}
11 changes: 11 additions & 0 deletions internal/components/response.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package components

import "github.com/rivo/tview"

// Create a component to show response
func CreateResponse() *tview.TextView {
c := tview.NewTextView()
c.SetText("")

return c
}
49 changes: 49 additions & 0 deletions internal/db/db.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package db

import "database/sql"

var db *sql.DB

func createConnection() error {
if db == nil {
newConnection, err := sql.Open("sqlite3", "gorest.db")

if err != nil {
return err
}

db = newConnection
}

if err := db.Ping(); err != nil {
return err
}

return nil
}

func init() {
err := createConnection()

if err != nil {
panic(err)
}

// Define the SQL statement to create the table.
createTableSQL := `
CREATE TABLE IF NOT EXISTS requests (
id INTEGER PRIMARY KEY AUTOINCREMENT,
url TEXT,
name TEXT,
method TEXT,
headers TEXT,
body TEXT
);
`

// Execute the SQL statement to create the table.
_, err = db.Exec(createTableSQL)
if err != nil {
panic(err)
}
}
47 changes: 47 additions & 0 deletions internal/gorest/gorest.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package gorest

import (
uicontainers "github.com/NathanFirmo/gorest/internal/ui-containers"
"github.com/rivo/tview"
)

// Gorest application
type App struct {
tview *tview.Application
rootContainer *tview.Flex
requestsList *uicontainers.RequestsListContainer
request *uicontainers.RequestContainer
response *uicontainers.ResponseContainer
mode int
}

// Create gorest application and initialize components
func CreateApp() *App {
requestContainer := uicontainers.CreateRequest()
responseContainer := uicontainers.CreateResponse()
requestsListContainer := uicontainers.CreateRequestsList()

a := App{
tview: tview.NewApplication(),
rootContainer: tview.NewFlex(),
request: requestContainer,
response: responseContainer,
requestsList: requestsListContainer,
}

// Configure root layout
a.rootContainer.AddItem(a.requestsList.Container, 0, 1, true).
AddItem(a.request.Container, 0, 2, false).
AddItem(a.response.Container, 0, 2, false)
a.tview.SetRoot(a.rootContainer, true).SetFocus(a.rootContainer).EnableMouse(true)

a.tview.SetFocus(a.requestsList.Component.Component)
a.SetInputHandlers()

return &a
}

// Start gorest application
func (a App) Start() error {
return a.tview.Run()
}
71 changes: 71 additions & 0 deletions internal/gorest/input-handler.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
package gorest

import (
"github.com/NathanFirmo/gorest/internal/components"
"github.com/NathanFirmo/gorest/internal/utils"
"github.com/gdamore/tcell/v2"
)

const (
KeyI = 256
)

func (app *App) SetInputHandlers() {
// Sets an functions that intercepts keyboard inputs and allows to check pressed key and handle focus
app.rootContainer.SetInputCapture(func(event *tcell.EventKey) *tcell.EventKey {
focus := app.tview.GetFocus()

switch event.Key() {
case tcell.KeyCtrlL:
if focus == app.requestsList.Component.Component || focus == app.requestsList.Container {
app.tview.SetFocus(app.request.UrlInputComponent)
} else if focus == app.request.UrlInputComponent || focus == app.request.OptionsComponent {
app.tview.SetFocus(app.response.Container)
}
return event
case tcell.KeyCtrlH:
if focus == app.response.Container {
app.tview.SetFocus(app.request.UrlInputComponent)
} else if focus == app.request.UrlInputComponent || focus == app.request.OptionsComponent {
app.tview.SetFocus(app.requestsList.Component.Component)
}
return event
case tcell.KeyCtrlJ:
if focus == app.request.UrlInputComponent {
app.tview.SetFocus(app.request.OptionsComponent)
}
return event
case tcell.KeyCtrlK:
if focus == app.request.OptionsComponent {
app.tview.SetFocus(app.request.UrlInputComponent)
}
return event
case tcell.KeyEnter:
url := app.request.UrlInputComponent.GetText()
res, _ := utils.MakeRequest(url)
app.response.Component.SetText(string(res))
case tcell.KeyCtrlN:
length := app.requestsList.Component.Component.GetItemCount()
app.requestsList.Component.AddItem(&components.Request{
Url: "",
Name: "New request",
Method: "GET",
Headers: "",
Body: "",
}, func() {
_, url := app.requestsList.Component.Component.GetItemText(length)
app.request.UrlInputComponent.SetText(url)
app.tview.SetFocus(app.request.UrlInputComponent)
})
app.requestsList.Component.Component.SetCurrentItem(length)
}

return event
})

app.request.UrlInputComponent.SetChangedFunc(func(url string) {
index := app.requestsList.Component.Component.GetCurrentItem()
main, _ := app.requestsList.Component.Component.GetItemText(index)
app.requestsList.Component.Component.SetItemText(index, main, url)
})
}
1 change: 1 addition & 0 deletions internal/gorest/theme.go
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
package gorest
32 changes: 32 additions & 0 deletions internal/ui-containers/request.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package uicontainers

import (
"github.com/NathanFirmo/gorest/internal/components"
"github.com/rivo/tview"
)

type RequestContainer struct {
Container *tview.Flex
OptionsComponent *tview.TextArea
UrlInputComponent *tview.InputField
}

// Create a flex container with row alignment to put request option components
func CreateRequest() *RequestContainer {
container := tview.NewFlex()
container.SetDirection(tview.FlexRow).SetBorder(true).SetTitle("Request")

reqOpt := components.CreateRequestOptionsInput()
reqUrlInput := components.CreateUrlInput()

// Add requests component on its container
container.
AddItem(reqUrlInput, 0, 1, false).
AddItem(reqOpt, 0, 9, false)

return &RequestContainer{
Container: container,
OptionsComponent: reqOpt,
UrlInputComponent: reqUrlInput,
}
}
Loading

0 comments on commit 28c3796

Please sign in to comment.