feat(BREAKING): specify project path #8
5 changed files with 94 additions and 45 deletions
|
@ -1,21 +1,77 @@
|
||||||
= Pelican
|
= 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.
|
Pelican is a simple Kanban board for your terminal.
|
||||||
|
|
||||||
== Storage
|
|
||||||
|
|
||||||
Data is stored in a https://github.com/etcd-io/bbolt[BoltDB] database.
|
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
|
Pelican does not make any assumptions to the path of the database file;
|
||||||
If $XDG\_DATA\_HOME is not set then the default location is $HOME/.local/share/canal/canal.db by default.
|
instead the user is expected to specify the path when running the application.
|
||||||
For all other operating systems the default location is $HOME/.canal/canal.db.
|
|
||||||
|
== 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
|
== 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
|
== Inspiration
|
||||||
|
|
||||||
|
|
|
@ -2,12 +2,20 @@ package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"log"
|
"log"
|
||||||
|
"os"
|
||||||
|
|
||||||
"codeflow.dananglin.me.uk/apollo/pelican/internal/ui"
|
"codeflow.dananglin.me.uk/apollo/pelican/internal/ui"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
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 {
|
if err := pelican.Run(); err != nil {
|
||||||
log.Fatalf("Error: an error occurred while running pelican, %s", err)
|
log.Fatalf("Error: an error occurred while running pelican, %s", err)
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
package board
|
package board
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"sort"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"sort"
|
||||||
)
|
)
|
||||||
|
|
||||||
type StatusListEmptyError struct{}
|
type StatusListEmptyError struct{}
|
||||||
|
|
|
@ -5,7 +5,6 @@ import (
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
"codeflow.dananglin.me.uk/apollo/pelican/internal/board"
|
"codeflow.dananglin.me.uk/apollo/pelican/internal/board"
|
||||||
"github.com/gdamore/tcell/v2"
|
|
||||||
"github.com/rivo/tview"
|
"github.com/rivo/tview"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -37,7 +36,12 @@ type UI struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewUI returns a new UI value.
|
// 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{
|
ui := UI{
|
||||||
Application: tview.NewApplication(),
|
Application: tview.NewApplication(),
|
||||||
pages: tview.NewPages(),
|
pages: tview.NewPages(),
|
||||||
|
@ -47,13 +51,15 @@ func NewUI() UI {
|
||||||
focusedColumn: 0,
|
focusedColumn: 0,
|
||||||
columns: nil,
|
columns: nil,
|
||||||
move: nil,
|
move: nil,
|
||||||
board: board.Board{},
|
board: b,
|
||||||
deleteCardModal: tview.NewModal(),
|
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.
|
// closeBoard closes the board.
|
||||||
|
@ -78,7 +84,7 @@ func (u *UI) deleteCard() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// init initialises the UI.
|
// init initialises the UI.
|
||||||
func (u *UI) init() {
|
func (u *UI) init() error {
|
||||||
u.pages.AddPage(mainPageName, u.flex, true, true)
|
u.pages.AddPage(mainPageName, u.flex, true, true)
|
||||||
|
|
||||||
u.initQuitModal()
|
u.initQuitModal()
|
||||||
|
@ -90,18 +96,13 @@ func (u *UI) init() {
|
||||||
u.initDeleteCardModal()
|
u.initDeleteCardModal()
|
||||||
u.pages.AddPage(deleteCardPageName, u.deleteCardModal, false, false)
|
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)
|
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.
|
// initAddInputModal initialises the add input modal.
|
||||||
|
@ -168,22 +169,6 @@ func (u *UI) newCard(title, content string) error {
|
||||||
return nil
|
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.
|
// refresh refreshes the UI.
|
||||||
func (u *UI) refresh() error {
|
func (u *UI) refresh() error {
|
||||||
statusList, err := u.board.StatusList()
|
statusList, err := u.board.StatusList()
|
||||||
|
|
|
@ -41,7 +41,7 @@ func Lint() error {
|
||||||
|
|
||||||
// Build build the executable
|
// Build build the executable
|
||||||
func Build() error {
|
func Build() error {
|
||||||
main := "./cmd/"+binary+"/main.go"
|
main := "./cmd/" + binary + "/main.go"
|
||||||
return sh.Run("go", "build", "-o", binary, main)
|
return sh.Run("go", "build", "-o", binary, main)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue