Compare commits

..

No commits in common. "309277a1154fb1660a276982a00363261474794b" and "1cac8904da4e58bee4d460359ef8102bb5094cf0" have entirely different histories.

11 changed files with 21 additions and 285 deletions

View File

@ -10,8 +10,7 @@ LDFLAGS=\
test \
docs \
pomo-build \
readme \
bin/pomo
readme
default: bin/pomo test
@ -29,11 +28,6 @@ test:
install:
go install ./cmd/...
man/pomo.1: man/pomo.1.scd
scdoc < $< > $@
manpages: man/pomo.1
docs: www/data/readme.json
cd www && hugo -d ../docs

View File

@ -49,7 +49,7 @@ pomo start -t my-project "write some codes"
## Configuration
Pomo has a few configuration options which can be read from a JSON file in Pomo's config directory `~/.config/pomo/config.json`.
Pomo has a few configuration options which can be read from a JSON file in Pomo's state directory `~/.pomo/config.json`.
### colors
@ -65,33 +65,6 @@ Example:
}
```
### Execute command on state change
Pomo will execute an arbitrary command specified in the array argument `onEvent`
when the state changes. The first element of this array should be the
executable to run while the remaining elements are space delimited arguments.
The new state will be exported as an environment variable `POMO_STATE` for this
command. Possible state values are `RUNNING`, `PAUSED`, `BREAKING`, or
`COMPLETE`.
For example, to trigger a terminal bell when a session completes, add the
following to `config.json`:
```json
...
"onEvent": ["/bin/sh", "/path/to/script/my_script.sh"],
...
```
where the contents of `my_script.sh` are
```bash
#!/bin/sh
if [ "$POMO_STATE" == "COMPLETE" ] ; then
echo -e '\a'
fi
```
See the `contrib` directory for user contributed scripts for use with `onEvent`.
## Integrations
By default pomo will setup a Unix socket and serve it's status there.

View File

View File

@ -1,3 +0,0 @@
#!/bin/sh
echo -e '\e'

View File

@ -1,5 +0,0 @@
#!/bin/sh
if [ "$POMO_STATE" == "BREAKING" ] ; then
swaynag -m "It's time to take a break!"
fi

View File

@ -1,89 +0,0 @@
.\" Generated by scdoc 1.11.2
.\" Complete documentation for this program is not available as a GNU info page
.ie \n(.g .ds Aq \(aq
.el .ds Aq '
.nh
.ad l
.\" Begin generated content:
.TH "pomo" "1" "2022-05-30"
.P
.SH NAME
.P
\fBPomo\fR is a simple CLI for using the Pomodoro Technique.\&
.P
.SH SYNOPSIS
.P
\fBpomo\fR [OPTIONS] COMMAND [arg.\&.\&.\&]
.P
.SH DESCRIPTION
.P
\fBpomo\fR helps you track what you did, how long it took you to do it,
and how much effort you expect it to take.\&
.P
The Pomodoro Technique is simple and effective:
.P
.RS 4
\fB\fR Decide on a task you want to accomplish
\fB\fR Break the task into timed intervals (pomodoros), [approx.\& 25 min]
\fB\fR After each pomodoro take a short break [approx.\& 3 - 5 min]
\fB\fR Once all pomodoros are completed take a longer break [approx 15 - 20 min]
\fB\fR Repeat
.P
.RE
.SH SUBCOMMANDS
.P
See --help for the complete command usage
.P
.nf
.RS 4
start, s start a new task
init initialize the sqlite database
config, cf display the current configuration
create, c create a new task without starting
begin, b begin requested pomodoro
list, l list historical tasks
delete, d delete a stored task
status, st output the current status
.fi
.RE
.P
.SH CONFIGURATION
.P
Pomo has a configuration file that is stored in \fB~/.\&config/pomo/config.\&json\fR.\&
.P
.nf
.RS 4
{
"colors": null,
"dateTimeFmt": "2006-01-02 15:04",
"publish": false,
"publishJson": false,
"publishSocketPath": ""
}
.fi
.RE
.P
.SH EXAMPLES
.P
.SS GETTING STARTED
.P
.nf
.RS 4
# ensure your database has been initialized
pomo init
# run a new pomodoro
pomo start -t my-project "write some code"
# once finished view previously completed pomodoros
pomo list
.fi
.RE
.P
.SH SEE ALSO
.P
See the pomo source repository on Github at https://github.\&com/kevinschoon/pomo for complete documentation.\&
.P
.SH AUTHORS
.P
Written by Kevin Schoon <me@kevinschoon.\&com> with help from the open source
community.\&

View File

@ -1,74 +0,0 @@
pomo(1)
# NAME
*Pomo* is a simple CLI for using the Pomodoro Technique.
# SYNOPSIS
*pomo* [OPTIONS] COMMAND [arg...]
# DESCRIPTION
*pomo* helps you track what you did, how long it took you to do it,
and how much effort you expect it to take.
The Pomodoro Technique is simple and effective:
** Decide on a task you want to accomplish
** Break the task into timed intervals (pomodoros), [approx. 25 min]
** After each pomodoro take a short break [approx. 3 - 5 min]
** Once all pomodoros are completed take a longer break [approx 15 - 20 min]
** Repeat
# SUBCOMMANDS
See --help for the complete command usage
```
start, s start a new task
init initialize the sqlite database
config, cf display the current configuration
create, c create a new task without starting
begin, b begin requested pomodoro
list, l list historical tasks
delete, d delete a stored task
status, st output the current status
```
# CONFIGURATION
Pomo has a configuration file that is stored in *~/.config/pomo/config.json*.
```
{
"colors": null,
"dateTimeFmt": "2006-01-02 15:04",
"publish": false,
"publishJson": false,
"publishSocketPath": ""
}
```
# EXAMPLES
## GETTING STARTED
```
# ensure your database has been initialized
pomo init
# run a new pomodoro
pomo start -t my-project "write some code"
# once finished view previously completed pomodoros
pomo list
```
# SEE ALSO
See the pomo source repository on Github at https://github.com/kevinschoon/pomo for complete documentation.
# AUTHORS
Written by Kevin Schoon <me@kevinschoon.com> with help from the open source
community.

View File

@ -23,7 +23,6 @@ type Config struct {
DBPath string `json:"dbPath"`
SocketPath string `json:"socketPath"`
IconPath string `json:"iconPath"`
OnEvent []string `json:"onEvent"`
// Publish pushes updates to the configured
// SocketPath rather than listening for requests
Publish bool `json:"publish"`

View File

@ -2,10 +2,6 @@ package pomo
import (
"database/sql"
"fmt"
"os"
"os/exec"
"sync"
"time"
)
@ -23,8 +19,6 @@ type TaskRunner struct {
toggle chan bool
notifier Notifier
duration time.Duration
mu sync.Mutex
onEvent []string
}
func NewMockedTaskRunner(task *Task, store *Store, notifier Notifier) (*TaskRunner, error) {
@ -34,7 +28,7 @@ func NewMockedTaskRunner(task *Task, store *Store, notifier Notifier) (*TaskRunn
nPomodoros: task.NPomodoros,
origDuration: task.Duration,
store: store,
state: CREATED,
state: State(0),
pause: make(chan bool),
toggle: make(chan bool),
notifier: notifier,
@ -59,7 +53,6 @@ func NewTaskRunner(task *Task, config *Config) (*TaskRunner, error) {
toggle: make(chan bool),
notifier: NewXnotifier(config.IconPath),
duration: task.Duration,
onEvent: config.OnEvent,
}
return tr, nil
}
@ -78,34 +71,6 @@ func (t *TaskRunner) TimePauseDuration() time.Duration {
func (t *TaskRunner) SetState(state State) {
t.state = state
// execute onEvent command if variable is set
if t.onEvent != nil {
go t.runOnEvent()
}
}
// execute script command specified by `onEvent` on state change
func (t *TaskRunner) runOnEvent() error {
var cmd *exec.Cmd
// parse command arguments
numArgs := len(t.onEvent)
app := t.onEvent[0]
if numArgs > 1 {
args := t.onEvent[1:(numArgs + 1)]
cmd = exec.Command(app, args...)
} else {
cmd = exec.Command(app)
}
// set state in command environment
cmd.Env = append(os.Environ(),
fmt.Sprintf("POMO_STATE=%s", t.state),
)
// run command
err := cmd.Run()
if err != nil {
return err
}
return nil
}
func (t *TaskRunner) run() error {
@ -125,6 +90,7 @@ func (t *TaskRunner) run() error {
loop:
select {
case <-timer.C:
t.SetState(BREAKING)
t.stopped = time.Now()
t.count++
case <-t.toggle:
@ -160,7 +126,7 @@ func (t *TaskRunner) run() error {
if t.count == t.nPomodoros {
break
}
t.SetState(BREAKING)
t.notifier.Notify("Pomo", "It is time to take a break!")
// Reset the duration incase it
// was paused.
@ -175,25 +141,15 @@ func (t *TaskRunner) run() error {
}
func (t *TaskRunner) Toggle() {
t.mu.Lock()
defer t.mu.Unlock()
if t.state == BREAKING {
t.toggle <- true
}
t.toggle <- true
}
func (t *TaskRunner) Pause() {
t.mu.Lock()
defer t.mu.Unlock()
if t.state == PAUSED || t.state == RUNNING {
t.pause <- true
}
t.pause <- true
}
func (t *TaskRunner) Status() *Status {
return &Status{
TaskID: t.taskID,
TaskMessage: t.taskMessage,
State: t.state,
Count: t.count,
NPomodoros: t.nPomodoros,

View File

@ -12,8 +12,6 @@ type State int
func (s State) String() string {
switch s {
case CREATED:
return "CREATED"
case RUNNING:
return "RUNNING"
case BREAKING:
@ -27,8 +25,7 @@ func (s State) String() string {
}
const (
CREATED State = iota
RUNNING
RUNNING State = iota + 1
BREAKING
COMPLETE
PAUSED
@ -105,8 +102,6 @@ func (p Pomodoro) Duration() time.Duration {
// Status is used to communicate the state
// of a running Pomodoro session
type Status struct {
TaskID int `json:"task_id"`
TaskMessage string `json:"task_message"`
State State `json:"state"`
Remaining time.Duration `json:"remaining"`
Pauseduration time.Duration `json:"pauseduration"`

View File

@ -14,8 +14,6 @@ func setContent(wheel *Wheel, status *Status, par *widgets.Paragraph) {
par.Text = fmt.Sprintf(
`[%d/%d] Pomodoros completed
Current Task: %s
%s %s remaining
@ -23,7 +21,6 @@ func setContent(wheel *Wheel, status *Status, par *widgets.Paragraph) {
`,
status.Count,
status.NPomodoros,
status.TaskMessage,
wheel,
status.Remaining,
)
@ -32,29 +29,26 @@ func setContent(wheel *Wheel, status *Status, par *widgets.Paragraph) {
par.Text = fmt.Sprintf(
`It is time to take a break!
Once you are ready, press [Enter]
to begin the next Pomodoro
%s %s break duration
%s %s pause duration
[q] - quit
[q] - quit [p] - pause
`,
wheel,
status.Pauseduration,
)
case PAUSED:
par.Text = fmt.Sprintf(`Pomo is suspended.
Current Task: %s
par.Text = `Pomo is suspended.
Press [p] to continue.
[q] - quit [p] - unpause
`,
status.TaskMessage,
)
Press [p] to continue.
[q] - quit [p] - unpause
`
case COMPLETE:
par.Text = `This session has concluded.
@ -89,20 +83,16 @@ func StartUI(runner *TaskRunner) {
resize := func() {
termWidth, termHeight := ui.TerminalDimensions()
// for RUNNING and PAUSED states
x1 := (termWidth - 50) / 2
x2 := x1 + 50
y1 := (termHeight - 10) / 2
y2 := y1 + 10
y1 := (termHeight - 8) / 2
y2 := y1 + 8
switch runner.state {
case BREAKING:
y1 = (termHeight - 11) / 2
y2 = y1 + 11
case COMPLETE:
y1 = (termHeight - 8) / 2
y2 = y1 + 8
y1 = (termHeight - 12) / 2
y2 = y1 + 12
}
par.SetRect(x1, y1, x2, y2)