Create/Delete note, Clean up code
This commit is contained in:
parent
3ef0fbe76f
commit
e7d12dc1d7
105
api.go
Normal file
105
api.go
Normal file
@ -0,0 +1,105 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
type note struct {
|
||||
Id int64 `json:"id"`
|
||||
Title string `json:"title"`
|
||||
Content string `json:"content"`
|
||||
}
|
||||
|
||||
const endpoint = "http://localhost:8080/api"
|
||||
|
||||
func loadNotes() ([]note, error) {
|
||||
res, err := http.Get(endpoint + "/notes")
|
||||
if err != nil {
|
||||
return []note{}, nil
|
||||
}
|
||||
|
||||
data, err := io.ReadAll(res.Body)
|
||||
if err != nil {
|
||||
return []note{}, nil
|
||||
}
|
||||
|
||||
var loadedNotes []note
|
||||
json.Unmarshal(data, &loadedNotes)
|
||||
return loadedNotes, nil
|
||||
}
|
||||
|
||||
func putNote(n note) error {
|
||||
json, err := json.Marshal(n)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
req, err := http.NewRequest("PUT", endpoint+"/notes/"+fmt.Sprint(n.Id), bytes.NewReader(json))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
req.Header.Add("Content-Type", "application/json")
|
||||
|
||||
res, err := http.DefaultClient.Do(req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if res.StatusCode != http.StatusOK {
|
||||
return errors.New("Request failed: " + res.Status)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func postNote(n note) (note, error) {
|
||||
jsonBytes, err := json.Marshal(n)
|
||||
if err != nil {
|
||||
return note{}, err
|
||||
}
|
||||
|
||||
res, err := http.Post(endpoint+"/notes", "application/json", bytes.NewReader(jsonBytes))
|
||||
if err != nil {
|
||||
return note{}, err
|
||||
}
|
||||
|
||||
if res.StatusCode != http.StatusCreated {
|
||||
return note{}, errors.New("Request failed: " + res.Status)
|
||||
}
|
||||
|
||||
resBytes, err := io.ReadAll(res.Body)
|
||||
if err != nil {
|
||||
return note{}, err
|
||||
}
|
||||
|
||||
err = json.Unmarshal(resBytes, &n)
|
||||
if err != nil {
|
||||
return note{}, err
|
||||
}
|
||||
|
||||
return n, nil
|
||||
}
|
||||
|
||||
func deleteNote(n note) error {
|
||||
req, err := http.NewRequest("DELETE", endpoint+"/notes/"+fmt.Sprint(n.Id), bytes.NewReader([]byte{}))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
res, err := http.DefaultClient.Do(req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if res.StatusCode != http.StatusOK {
|
||||
return errors.New("Request failed: " + res.Status)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
219
main.go
219
main.go
@ -1,13 +1,9 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strings"
|
||||
@ -17,72 +13,18 @@ import (
|
||||
"github.com/mattn/go-runewidth"
|
||||
)
|
||||
|
||||
// TODO new, delete
|
||||
|
||||
type note struct {
|
||||
Id int64 `json:"id"`
|
||||
Title string `json:"title"`
|
||||
Content string `json:"content"`
|
||||
}
|
||||
|
||||
const lineHeight = 2
|
||||
const editor = "vim"
|
||||
|
||||
const endpoint = "http://localhost:8080/api"
|
||||
const (
|
||||
uiMain = 0
|
||||
uiDelete = 1
|
||||
)
|
||||
|
||||
var uiState = uiMain
|
||||
var selectedNote = 0
|
||||
var notes []note
|
||||
|
||||
func emitStr(s tcell.Screen, x int, y int, style tcell.Style, str string) {
|
||||
for _, c := range str {
|
||||
var comb []rune
|
||||
w := runewidth.RuneWidth(c)
|
||||
|
||||
if w == 0 {
|
||||
comb = []rune{c}
|
||||
c = ' '
|
||||
w = 1
|
||||
}
|
||||
|
||||
s.SetContent(x, y, c, comb, style)
|
||||
x += w
|
||||
}
|
||||
}
|
||||
|
||||
func showNotes(s tcell.Screen) {
|
||||
s.Fill(' ', tcell.StyleDefault)
|
||||
|
||||
for idx, note := range notes {
|
||||
style := tcell.StyleDefault
|
||||
|
||||
if idx == selectedNote {
|
||||
style = style.Foreground(tcell.ColorBlack).Background(tcell.ColorWhite)
|
||||
}
|
||||
|
||||
text := fmt.Sprint(idx) + ". " + note.Title
|
||||
emitStr(s, 1, 1+idx*lineHeight, style, text)
|
||||
}
|
||||
|
||||
_, h := s.Size()
|
||||
emitStr(s, 1, h-1, tcell.StyleDefault.Foreground(tcell.ColorBlue), "n - new, r - rename, d - delete, Enter - edit, Esc - exit")
|
||||
}
|
||||
|
||||
func loadNotes() {
|
||||
res, err := http.Get(endpoint + "/notes")
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
|
||||
data, err := io.ReadAll(res.Body)
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
|
||||
var loadedNotes []note
|
||||
json.Unmarshal(data, &loadedNotes)
|
||||
notes = loadedNotes
|
||||
}
|
||||
|
||||
func edit(s tcell.Screen, text string, ext string) (string, error) {
|
||||
cmd := exec.Command("vipe", "--suffix", ext)
|
||||
cmd.Env = append(cmd.Env, "EDITOR="+editor)
|
||||
@ -111,31 +53,6 @@ func edit(s tcell.Screen, text string, ext string) (string, error) {
|
||||
return text, nil
|
||||
}
|
||||
|
||||
func putNote(n note) error {
|
||||
json, err := json.Marshal(n)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
req, err := http.NewRequest("PUT", endpoint+"/notes/"+fmt.Sprint(n.Id), bytes.NewReader(json))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
req.Header.Add("Content-Type", "application/json")
|
||||
|
||||
res, err := http.DefaultClient.Do(req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if res.StatusCode != 200 {
|
||||
return errors.New("Request failed: " + res.Status)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func editNote(s tcell.Screen, n note) (note, error) {
|
||||
newContent, err := edit(s, n.Content, "md")
|
||||
if err != nil {
|
||||
@ -183,8 +100,65 @@ func editNoteTitle(s tcell.Screen, n note) (note, error) {
|
||||
return n, nil
|
||||
}
|
||||
|
||||
func emitStr(s tcell.Screen, x int, y int, style tcell.Style, str string) {
|
||||
for _, c := range str {
|
||||
var comb []rune
|
||||
w := runewidth.RuneWidth(c)
|
||||
|
||||
if w == 0 {
|
||||
comb = []rune{c}
|
||||
c = ' '
|
||||
w = 1
|
||||
}
|
||||
|
||||
s.SetContent(x, y, c, comb, style)
|
||||
x += w
|
||||
}
|
||||
}
|
||||
|
||||
func showNotes(s tcell.Screen) {
|
||||
uiState = uiMain
|
||||
|
||||
s.Fill(' ', tcell.StyleDefault)
|
||||
|
||||
for idx, note := range notes {
|
||||
style := tcell.StyleDefault
|
||||
|
||||
if idx == selectedNote {
|
||||
style = style.Foreground(tcell.ColorBlack).Background(tcell.ColorWhite)
|
||||
}
|
||||
|
||||
text := fmt.Sprint(idx) + ". " + note.Title
|
||||
emitStr(s, 1, 1+idx*lineHeight, style, text)
|
||||
}
|
||||
|
||||
_, h := s.Size()
|
||||
emitStr(s, 1, h-1, tcell.StyleDefault.Foreground(tcell.ColorBlue), "n - new, r - rename, d - delete, Enter - edit, Esc - exit")
|
||||
}
|
||||
|
||||
func showDelete(s tcell.Screen) {
|
||||
uiState = uiDelete
|
||||
|
||||
s.Fill(' ', tcell.StyleDefault)
|
||||
emitStr(s, 1, 1, tcell.StyleDefault, "Do you really want to delete the note '"+notes[selectedNote].Title+"'?")
|
||||
emitStr(s, 1, 3, tcell.StyleDefault.Foreground(tcell.ColorBlue), "y - yes, n - no")
|
||||
}
|
||||
|
||||
func showUI(s tcell.Screen) {
|
||||
switch uiState {
|
||||
case uiMain:
|
||||
showNotes(s)
|
||||
case uiDelete:
|
||||
showDelete(s)
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
loadNotes()
|
||||
var err error
|
||||
notes, err = loadNotes()
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
|
||||
s, err := tcell.NewScreen()
|
||||
if err != nil {
|
||||
@ -203,9 +177,11 @@ func main() {
|
||||
for {
|
||||
switch ev := s.PollEvent().(type) {
|
||||
case *tcell.EventResize:
|
||||
showNotes(s)
|
||||
showUI(s)
|
||||
s.Sync()
|
||||
case *tcell.EventKey:
|
||||
switch uiState {
|
||||
case uiMain:
|
||||
switch ev.Key() {
|
||||
case tcell.KeyUp:
|
||||
if selectedNote > 0 {
|
||||
@ -232,8 +208,13 @@ func main() {
|
||||
|
||||
notes[selectedNote] = n
|
||||
|
||||
case tcell.KeyEscape:
|
||||
s.Fini()
|
||||
os.Exit(1)
|
||||
|
||||
case tcell.KeyRune:
|
||||
if ev.Rune() == 'r' {
|
||||
switch ev.Rune() {
|
||||
case 'r':
|
||||
n, err := editNoteTitle(s, notes[selectedNote])
|
||||
if err != nil {
|
||||
s.Fini()
|
||||
@ -244,11 +225,63 @@ func main() {
|
||||
|
||||
showNotes(s)
|
||||
s.Sync()
|
||||
|
||||
case 'n':
|
||||
title, err := edit(s, "", "txt")
|
||||
if err != nil {
|
||||
s.Fini()
|
||||
log.Fatalln(err)
|
||||
}
|
||||
|
||||
case tcell.KeyEscape:
|
||||
if len(title) == 0 {
|
||||
showNotes(s)
|
||||
s.Sync()
|
||||
break
|
||||
}
|
||||
|
||||
n2, err := postNote(note{Title: title})
|
||||
if err != nil {
|
||||
s.Fini()
|
||||
os.Exit(1)
|
||||
log.Fatalln(err)
|
||||
}
|
||||
|
||||
notes = append(notes, n2)
|
||||
|
||||
selectedNote = len(notes) - 1
|
||||
|
||||
showNotes(s)
|
||||
s.Sync()
|
||||
|
||||
case 'd':
|
||||
showDelete(s)
|
||||
s.Show()
|
||||
}
|
||||
}
|
||||
|
||||
case uiDelete:
|
||||
switch ev.Key() {
|
||||
case tcell.KeyRune:
|
||||
switch ev.Rune() {
|
||||
case 'y':
|
||||
err := deleteNote(notes[selectedNote])
|
||||
if err != nil {
|
||||
s.Fini()
|
||||
log.Fatalln(err)
|
||||
}
|
||||
|
||||
notes = append(notes[:selectedNote], notes[selectedNote+1:]...)
|
||||
|
||||
if selectedNote >= len(notes) {
|
||||
selectedNote = len(notes) - 1
|
||||
}
|
||||
|
||||
showNotes(s)
|
||||
s.Show()
|
||||
case 'n':
|
||||
showNotes(s)
|
||||
s.Show()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user