Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/master' into 50-readme
Browse files Browse the repository at this point in the history
  • Loading branch information
alanxoc3 committed Oct 2, 2020
2 parents d2ac99e + 5506b81 commit 4188731
Show file tree
Hide file tree
Showing 22 changed files with 407 additions and 261 deletions.
8 changes: 6 additions & 2 deletions internal/deck/deck.go
Original file line number Diff line number Diff line change
Expand Up @@ -118,14 +118,18 @@ func (d *Deck) ExecTop(input bool, now time.Time) (meta.Predict, error) {

// Step 2: Exec the predict value.
np := d.TopPredict().Exec(input, now)
no := meta.NewOutcomeFromPredict(&np, now, input)

// Step 3: Save the new prediction.
d.predictMap[np.Hash()] = &np

// Step 4: Set the current time.
// Step 4: Save the outcome too.
d.outcomeMap[no.Key()] = no

// Step 5: Set the current time.
d.stack.SetTime(now)

// Step 5: Update the stack.
// Step 6: Update the stack.
updateStatus := d.stack.Update(np.Hash(), np.Next())
internal.AssertLogic(updateStatus, "stack didn't contain hash")

Expand Down
1 change: 1 addition & 0 deletions internal/deck/deck_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,7 @@ func TestExecFuture(t *testing.T) {
assert.Equal(t, h2, *d.TopHash())
d.ExecTop(false, time.Date(2020,1,3,0,0,0,0,time.UTC))

assert.Len(t, d.OutcomeList(), 1)
assert.Equal(t, h1, *d.TopHash())
assert.Equal(t, 1, d.FutureLen())
}
Expand Down
51 changes: 25 additions & 26 deletions internal/file/argparse.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@ package file

import (
"fmt"
"github.com/alanxoc3/argparse"
"os"
"os/user"

"github.com/alanxoc3/argparse"
"github.com/alanxoc3/concards/internal"
)

type Config struct {
Expand All @@ -15,40 +17,28 @@ type Config struct {
IsPrint bool
IsStream bool

Editor string
Number int
MetaFile string
Files []string
Editor string
Number int
PredictFile string
OutcomeFile string
Files []string
}

// For debugging
func (c *Config) String() string {
return fmt.Sprintf(`IsReview %t
IsMemorize %t
IsDone %t
IsPrint %t
IsStream %t
Editor "%s"
Number %d
MetaFile "%s"
Files %s`, c.IsReview, c.IsMemorize, c.IsDone, c.IsPrint, c.IsStream, c.Editor, c.Number, c.MetaFile, c.Files)
}

func getDefaultEditor() string {
func defaultEditor() string {
if val, present := os.LookupEnv("EDITOR"); present {
return val
} else {
return "vi"
}
}

func getDefaultMeta() string {
if val, present := os.LookupEnv("CONCARDS_META"); present {
func defaultEnv(env string, file string) string {
if val, present := os.LookupEnv(env); present {
return val
} else if usr, err := user.Current(); err == nil {
return usr.HomeDir + "/.concards-meta"
return usr.HomeDir + "/.config/concards/" + file
} else {
return ".concards-meta"
return ""
}
}

Expand All @@ -63,8 +53,13 @@ func GenConfig(version string) *Config {
fDone := parser.Flag("d", "done", &argparse.Options{Help: "Show cards not available to be reviewed or memorized"})
fPrint := parser.Flag("p", "print", &argparse.Options{Help: "Prints all cards, one line per card"})
fNumber := parser.Int("n", "number", &argparse.Options{Default: 0, Help: "How many cards to review"})
fEditor := parser.String("E", "editor", &argparse.Options{Default: getDefaultEditor(), Help: "Which editor to use. Defaults to \"$EDITOR\""})
fMeta := parser.String("M", "meta", &argparse.Options{Default: getDefaultMeta(), Help: "Path to meta file. Defaults to \"$CONCARDS_META\" or \"~/.concards-meta\""})
fEditor := parser.String("E", "editor", &argparse.Options{Default: defaultEditor(), Help: "Defaults to \"$EDITOR\" or \"vi\""})
fPredictFile := parser.String("P", "predict", &argparse.Options{
Default: defaultEnv("CONCARDS_PREDICT", "predict"),
Help: "Defaults to \"$CONCARDS_PREDICT\" or \"~/.config/concards/predict\"" })
fOutcomeFile := parser.String("O", "outcome", &argparse.Options{
Default: defaultEnv("CONCARDS_OUTCOME", "outcome"),
Help: "Defaults to \"$CONCARDS_OUTCOME\" or \"~/.config/concards/outcome\"" })

parser.HelpFunc = func(c *argparse.Command, msg interface{}) string {
var help string
Expand Down Expand Up @@ -93,6 +88,9 @@ func GenConfig(version string) *Config {
os.Exit(0)
}

if *fPredictFile == "" { internal.AssertError("No predict file available.") }
if *fOutcomeFile == "" { internal.AssertError("No outcome file available.") }

c := &Config{}

c.IsReview = *fReview
Expand All @@ -103,7 +101,8 @@ func GenConfig(version string) *Config {

c.Editor = *fEditor
c.Number = *fNumber
c.MetaFile = *fMeta
c.PredictFile = *fPredictFile
c.OutcomeFile = *fOutcomeFile
c.Files = files

if !c.IsReview && !c.IsMemorize && !c.IsDone {
Expand Down
22 changes: 11 additions & 11 deletions internal/file/file_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,21 +35,21 @@ c 2020-02-01T00:00:00Z 2020-01-01T00:00:00Z 3 3 3 sm2`
func TestWritePredicts(t *testing.T) {
fstr := `a0000000000000000000000000000000 2020-02-01T00:00:00Z 2020-01-01T00:00:00Z 1 2 0 sm2
b0000000000000000000000000000000 2020-02-01T00:00:00Z 2020-01-01T00:00:00Z 0 0 0 sm2
c0000000000000000000000000000000 2020-02-01T00:00:00Z 2020-01-01T00:00:00Z 3 3 3 sm2`
c0000000000000000000000000000000 2020-02-01T00:00:00Z 2020-01-01T00:00:00Z 3 3 2 sm2`

predicts := []*meta.Predict{
meta.NewPredictFromStrings("a", "2020-02-01T00:00:00Z", "2020-01-01T00:00:00Z", "1", "2", "0", "sm2"),
meta.NewPredictFromStrings("b", "2020-02-01T00:00:00Z", "2020-01-01T00:00:00Z", "0", "0", "0", "sm2"),
meta.NewPredictFromStrings("c", "2020-02-01T00:00:00Z", "2020-01-01T00:00:00Z", "3", "3", "3", "sm2"),
}
predicts := []*meta.Predict{
meta.NewPredictFromStrings("a", "2020-02-01T00:00:00Z", "2020-01-01T00:00:00Z", "1", "2", "0", "sm2"),
meta.NewPredictFromStrings("b", "2020-02-01T00:00:00Z", "2020-01-01T00:00:00Z", "0", "0", "0", "sm2"),
meta.NewPredictFromStrings("c", "2020-02-01T00:00:00Z", "2020-01-01T00:00:00Z", "3", "3", "3", "sm2"),
}

assert.Equal(t, fstr, file.WritePredictsToString(predicts))
assert.Equal(t, fstr, file.WritePredictsToString(predicts))
}

func TestWritePredictsNotZero(t *testing.T) {
predicts := []*meta.Predict{
meta.NewPredictFromStrings("a", "0001-01-01T00:00:00Z", "0001-01-01T00:00:00Z", "0", "0", "0", "sm2"),
}
predicts := []*meta.Predict{
meta.NewPredictFromStrings("a", "0001-01-01T00:00:00Z", "0001-01-01T00:00:00Z", "0", "0", "0", "sm2"),
}

assert.Empty(t, file.WritePredictsToString(predicts))
assert.Empty(t, file.WritePredictsToString(predicts))
}
72 changes: 52 additions & 20 deletions internal/file/metafile.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,24 +2,25 @@ package file

import (
"bufio"
"fmt"
"io"
"io/ioutil"
"os"
"sort"
"strings"

"github.com/alanxoc3/concards/internal/meta"
)

// TODO: Clean up duplicate code here.

// Open filename and loads cards into new deck
func ReadPredictsFromFile(filename string) ([]*meta.Predict, error) {
if f, err := os.Open(filename); err != nil {
return nil, fmt.Errorf("Error: Unable to open meta file \"%s\".", filename)
} else {
defer f.Close()
return ReadPredictsFromReader(f), nil
func ReadPredictsFromFile(filename string) []*meta.Predict {
f, err := os.Open(filename)
if err != nil {
return []*meta.Predict{}
}

defer f.Close()
return ReadPredictsFromReader(f)
}

func ReadPredictsFromReader(r io.Reader) []*meta.Predict {
Expand All @@ -40,24 +41,55 @@ func ReadPredictsFromReader(r io.Reader) []*meta.Predict {
return list
}

func WritePredictsToFile(l []*meta.Predict, filename string) error {
str := []byte(WritePredictsToString(l))
err := ioutil.WriteFile(filename, str, 0644)
func WritePredictsToString(l []*meta.Predict) string {
predictStrings := []string{}
for _, v := range l {
if !v.IsZero() {
predictStrings = append(predictStrings, v.String())
}
}

sort.Strings(predictStrings)
return strings.Join(predictStrings, "\n")
}

// Open filename and loads cards into new deck
func ReadOutcomesFromFile(filename string) []*meta.Outcome {
f, err := os.Open(filename)
if err != nil {
return fmt.Errorf("Error: Writing to \"%s\" failed.", filename)
return []*meta.Outcome{}
}

return nil
defer f.Close()
return ReadOutcomesFromReader(f)
}

func WritePredictsToString(l []*meta.Predict) string {
predictStrings := []string{}
func ReadOutcomesFromReader(r io.Reader) []*meta.Outcome {
// Scan by words.
lineScanner := bufio.NewScanner(r)
lineScanner.Split(bufio.ScanLines)
list := []*meta.Outcome{}

for lineScanner.Scan() {
strs := strings.Fields(lineScanner.Text())

// Only add if there is something on the line.
if len(strs) > 0 {
list = append(list, meta.NewOutcomeFromStrings(strs...))
}
}

return list
}

func WriteOutcomesToString(l []*meta.Outcome) string {
outcomeStrings := []string{}
for _, v := range l {
if !v.IsZero() {
predictStrings = append(predictStrings, v.String())
}
if !v.IsZero() {
outcomeStrings = append(outcomeStrings, v.String())
}
}

sort.Strings(predictStrings)
return strings.Join(predictStrings, "\n")
sort.Strings(outcomeStrings)
return strings.Join(outcomeStrings, "\n")
}
53 changes: 53 additions & 0 deletions internal/file/write_files.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package file

import (
"fmt"
"io/ioutil"
"os"
"path/filepath"

"github.com/alanxoc3/concards/internal"
"github.com/alanxoc3/concards/internal/meta"
)

func createDir(path string) {
if err := os.MkdirAll(path, 0755); err != nil {
internal.AssertError(fmt.Sprintf("Problem creating directory \"%s\".", path))
}
}

func WritePredictsToFile(l []*meta.Predict, filename string) error {
createDir(filepath.Dir(filename))

err := ioutil.WriteFile(filename, []byte(WritePredictsToString(l)), 0644)
if err != nil {
return fmt.Errorf("Error: Writing to \"%s\" failed.", filename)
}

return nil
}

// TODO: clean me up please.
func WriteOutcomesToFile(l []*meta.Outcome, filename string) error {
outcomes := ReadOutcomesFromFile(filename)
outcomes = append(outcomes, l...)

outcomeMap := map[meta.Key]*meta.Outcome{}
for _, o := range outcomes {
outcomeMap[o.Key()] = o
}

outcomes = []*meta.Outcome{}
for _, v := range outcomeMap {
outcomes = append(outcomes, v)
}

createDir(filepath.Dir(filename))

err := ioutil.WriteFile(filename, []byte(WriteOutcomesToString(outcomes)), 0644)
if err != nil {
return fmt.Errorf("Error: Writing to \"%s\" failed.", filename)
}

return nil
}
13 changes: 13 additions & 0 deletions internal/hash_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package internal_test

import (
"testing"

"github.com/alanxoc3/concards/internal"
"github.com/stretchr/testify/assert"
)

func TestNewHash(t *testing.T) {
h := internal.NewHash("a")
assert.Equal(t, "a0000000000000000000000000000000", h.String())
}
53 changes: 53 additions & 0 deletions internal/history/hist.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package history

import (
"fmt"

"github.com/alanxoc3/concards/internal/deck"
)

type Manager struct {
decks []*deck.Deck
loc int
}

func NewManager() *Manager {
return &Manager{[]*deck.Deck{}, 0}
}

// Saves the deck onto the change stack.
func (m *Manager) Save(decks ...*deck.Deck) {
for _, d := range decks {
if len(m.decks) > 0 {
// Slice is exclusive, hence the +1
m.decks = m.decks[:m.loc+1]
}

m.decks = append(m.decks, d.Copy())
m.loc = len(m.decks) - 1
}
}

// Returns the state of the deck, error if there are no more redo operations.
func (m *Manager) Redo() (*deck.Deck, error) {
if m.loc+1 < len(m.decks) {
m.loc++
d := m.decks[m.loc]

return d, nil
} else {
return nil, fmt.Errorf("Nothing to redo.")
}
}

// Returns the state of the deck, error if there are no more undo operations.
func (m *Manager) Undo() (*deck.Deck, error) {
if m.loc > 0 {
m.loc--
d := m.decks[m.loc]

return d, nil
} else {
return nil, fmt.Errorf("Nothing to undo.")
}
}
Loading

0 comments on commit 4188731

Please sign in to comment.