feat(BREAKING): specify project path
All checks were successful
/ test (pull_request) Successful in 28s
/ lint (pull_request) Successful in 37s

This PR allows users to specify the path to the database file
Pelican now expects the user to specify the path to the project's
database file which allows users to open different projects.

This is a breaking change because Pelican no longer opens the
default path automatically. If no path is set then Pelican stops
with an error message.
This commit is contained in:
Dan Anglin 2023-12-12 12:47:58 +00:00
parent cf586a2b1d
commit fc5fa7b0ca
Signed by: dananglin
GPG key ID: 0C1D44CFBEE68638
5 changed files with 94 additions and 45 deletions

View file

@ -1,21 +1,77 @@
= Pelican
:toc:
:toclevels: 1
:toc-title: Contents
== Summary
== Overview
**This project is WIP and is not meant for production use**
**This project is WIP and is not meant for production use.**
Pelican is a simple Kanban board for your terminal.
== Storage
Data is stored in a https://github.com/etcd-io/bbolt[BoltDB] database.
For Linux the default the database file is located at $XDG\_DATA\_HOME/canal/canal.db
If $XDG\_DATA\_HOME is not set then the default location is $HOME/.local/share/canal/canal.db by default.
For all other operating systems the default location is $HOME/.canal/canal.db.
Pelican does not make any assumptions to the path of the database file;
instead the user is expected to specify the path when running the application.
== Installation
=== Requirements
==== Go
A minimum version of Go 1.21.0 is required for installing spruce.
Please go https://go.dev/dl/[here] to download the latest version.
==== Mage (Optional)
The project includes a https://codeflow.dananglin.me.uk/apollo/pelican/src/branch/main/magefiles/mage.go[magefile]
for automating the build and installation of the binary.
You can visit the https://magefile.org[website] for instructions on how to install Mage.
=== Install with Mage
TBC
=== Install with Go
If your `GOBIN` directory is included in your `PATH` then you can install Pelican with Go.
[source,console]
----
git clone https://codeflow.dananglin.me.uk/apollo/pelican.git
cd pelican
go install ./cmd/pelican
----
== Running Pelican
To create a new Kanban project with Pelican, simply run the following command:
[source,console]
----
pelican ./project.pelican
----
This will create a new BoltDB database file called `project.pelican` in your current directory
and initialises the database with an empty project.
== Keybindings
TBC
[%header,cols=2*]
|===
|Key
|Action
|CTRL + q
|Quit the application
|a
|Add card
|CTRL + d
|Delete card
|m
|Move card between statuses
|===
== Inspiration

View file

@ -2,12 +2,20 @@ package main
import (
"log"
"os"
"codeflow.dananglin.me.uk/apollo/pelican/internal/ui"
)
func main() {
pelican := ui.NewUI()
if len(os.Args) != 2 {
log.Fatalf("ERROR: Unexpected number of command-line arguments; want 1; got %d", len(os.Args)-1)
}
pelican, err := ui.NewUI(os.Args[1])
if err != nil {
log.Fatalf("ERROR: Unable to initialise Pelican; %v", err)
}
if err := pelican.Run(); err != nil {
log.Fatalf("Error: an error occurred while running pelican, %s", err)

View file

@ -1,8 +1,8 @@
package board
import (
"sort"
"fmt"
"sort"
)
type StatusListEmptyError struct{}

View file

@ -5,7 +5,6 @@ import (
"strconv"
"codeflow.dananglin.me.uk/apollo/pelican/internal/board"
"github.com/gdamore/tcell/v2"
"github.com/rivo/tview"
)
@ -37,7 +36,12 @@ type UI struct {
}
// NewUI returns a new UI value.
func NewUI() UI {
func NewUI(path string) (UI, error) {
b, err := board.Open(path)
if err != nil {
return UI{}, fmt.Errorf("unable to open the project's board; %w", err)
}
ui := UI{
Application: tview.NewApplication(),
pages: tview.NewPages(),
@ -47,13 +51,15 @@ func NewUI() UI {
focusedColumn: 0,
columns: nil,
move: nil,
board: board.Board{},
board: b,
deleteCardModal: tview.NewModal(),
}
ui.init()
if err := ui.init(); err != nil {
return UI{}, fmt.Errorf("received an error after running the initialisation; %w", err)
}
return ui
return ui, nil
}
// closeBoard closes the board.
@ -78,7 +84,7 @@ func (u *UI) deleteCard() {
}
// init initialises the UI.
func (u *UI) init() {
func (u *UI) init() error {
u.pages.AddPage(mainPageName, u.flex, true, true)
u.initQuitModal()
@ -90,18 +96,13 @@ func (u *UI) init() {
u.initDeleteCardModal()
u.pages.AddPage(deleteCardPageName, u.deleteCardModal, false, false)
u.SetInputCapture(func(event *tcell.EventKey) *tcell.EventKey {
switch event.Rune() {
case 'o':
if u.flex.HasFocus() && len(u.columns) == 0 {
_ = u.openBoard("")
}
}
return event
})
u.SetRoot(u.pages, true)
if err := u.refresh(); err != nil {
return fmt.Errorf("error refreshing the board, %w", err)
}
return nil
}
// initAddInputModal initialises the add input modal.
@ -168,22 +169,6 @@ func (u *UI) newCard(title, content string) error {
return nil
}
// openBoard opens the kanban board.
func (u *UI) openBoard(path string) error {
b, err := board.Open(path)
if err != nil {
return fmt.Errorf("unable to load board, %w", err)
}
u.board = b
if err = u.refresh(); err != nil {
return fmt.Errorf("error refreshing the board, %w", err)
}
return nil
}
// refresh refreshes the UI.
func (u *UI) refresh() error {
statusList, err := u.board.StatusList()

View file

@ -41,7 +41,7 @@ func Lint() error {
// Build build the executable
func Build() error {
main := "./cmd/"+binary+"/main.go"
main := "./cmd/" + binary + "/main.go"
return sh.Run("go", "build", "-o", binary, main)
}