Skip to content

Commit

Permalink
GH-30 Added escape character functionality.
Browse files Browse the repository at this point in the history
Along with that, I:
- Updated the README.
- Added a unit test.
- Removed old TODOs (GH-36).
  • Loading branch information
alanxoc3 committed Jul 18, 2020
1 parent 62bf613 commit 2395976
Show file tree
Hide file tree
Showing 4 changed files with 124 additions and 67 deletions.
117 changes: 57 additions & 60 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,74 +1,81 @@
<!-- @> concards | Console Cards | A cool + simple flashcard app. <@ -->
<!-- @> Who is the coolest person in the world? | You are :D. | Have a great day! <@ -->
# <img src="logo.svg" />

[![Build Status](https://travis-ci.org/alanxoc3/concards.svg?branch=master)](https://travis-ci.org/alanxoc3/concards)
[![Go Report Card](https://goreportcard.com/badge/github.com/alanxoc3/concards)](https://goreportcard.com/report/github.com/alanxoc3/concards)
[![Coverage Status](https://coveralls.io/repos/github/alanxoc3/concards/badge.svg?branch=master)](https://coveralls.io/github/alanxoc3/concards?branch=master)

Turning notes into flashcards. Concards is my ongoing attempt to make
flashcards simple and quick to record or embed into a text document. Unlike the
overhead of other flashcard applications, Concards accepts a minimal amount of
rules. This allows tons of freedom in the way you want to create your own
flashcards!
Turning notes into flashcards, or should I say concards! Concards is my ongoing
attempt to make flashcards simple and easily embeddable into text document
based notes. Concards is much lighter than other flashcard applications such as
such as [Anki](https://apps.ankiweb.net/) or
[Memrise](https://www.memrise.com/), but is also very powerful by following the
[Unix Philosophy](https://en.wikipedia.org/wiki/Unix_philosophy) of "Do one
thing and do it well".

## Features
- Implements the [SM2](https://www.supermemo.com/english/ol/sm2.htm) Repetition Algorithm.
- Beautiful terminal gui.
- Supports UTF-8!
- Reading in from multiple files & directories.
- Undoing/Redoing.
- Easily editing a card while reviewing your cards.

## Install
Install like any other go application.
Download the latest binary executable from the [release
page](https://github.com/alanxoc3/concards/releases). At the moment, only Linux
and Mac are supported.

### Building From Source
Use the `go install` command, passing in snapshot as the version concards
compiles with.
``` bash
go install github.com/alanxoc3/concards
~/$GOPATH/bin/concards --help
go install -ldflags="-X main.version=snapshot" github.com/alanxoc3/concards
```

## Features
* Implements the [SM2](https://www.supermemo.com/english/ol/sm2.htm) Repetition Algorithm.
* Beautiful terminal gui.
* Supports UTF-8!
* Reading in from multiple files.
* Undoing/Redoing
* Easily editing a card while reviewing your cards.
* And More!!!

## Usage
The file syntax was designed to be very simple and flexible, allowing anyone to
quickly embed flashcards into their text document without extra hassle of other
flashcard apps (like [Anki](https://apps.ankiweb.net/) or
[Memrise](https://www.memrise.com/)).

The syntax to embed your flashcards is like this:
The complete syntax of embedding your flashcards into text documents consists
of these keywords:
```
@> What is the answer?
| Here is the answer! <@
'@>' = Starts a concards block and also starts a question.
'|' = Separates sides.
'<@' = Ends the concards block.
'\' = Escapes the special tokens above.
```

Wanna try it out? Run concards on this `README.md` file!
``` bash
concards README.md
Here are a few example concards:
```
@> What does this mean 你好世界?
| Hello World
### A Simple Concard
```
@> This is a question.
| Answer #1
| Answer #2
| Answer #3 <@
```
@> What does "concards" stand for?
| Console Cards
### 3 Simple Concards
```
@> This is question #1. | Answer #1
@> This is question #2. | Answer #1 | Answer #2
@> This is question #3. | Answer #1 | Answer #2 | Answer #3 <@
```
@> Can a concard have more than 2 sides?
| Yes. | Yes it can.
@> What does a concard look like?
| \@> It could look like this \| What does a concard look like? \<@
| \@> It could also look like this \| with multiple \| sides! \<@
@> How do you escape a concard keyword?
| Put a backslash before it. Your text file would show "\@>", but the app shows "@>".
@> How do you show a backslash then a keyword in the concards ui?
| To see \\@> in the ui, your text document must have 2 backslashes: \\\@>
## All Special Tokens
All the special tokens that are a part of concards syntax are below.
@> The person who created concards.
| Alan Morgan
<@
```
@> = Starts a concards block. Starts a question.
<@ = Ends the concards block.
| = Separates answers.

The easiest way to understand that syntax is by trying it out! Just run
concards on this `README.md` file and see what happens!
``` bash
concards README.md
```

## Advanced Usage

### The Meta Data File
Here is an example meta-data file:
```
Expand All @@ -84,15 +91,5 @@ sha256sum cut in half | review timestamp | streak | alg | data
8525b45f883c05eec46b4f7a88e7f7ef | 2020-01-01T00:00:00Z | 0 | sm2 | 2.5
```

This file is saved in `$CONCARDS_META`. If that environment variable doesn't
exist, then it is saved in `$HOME/.concards-meta`.

## Dev TODOs
- TODO: Implement the [leitner system](https://en.wikipedia.org/wiki/Leitner_system)
- TODO: Rework the terminal GUI.
- TODO: Add file name to the GUI.
- TODO: Enable CTRL-L (reloads the display).
- TODO: Add ability to change algorithm in GUI.
- TODO: Create a web flashcard front-end too.
- TODO: Create a man page.
- TODO: Create my own version of arg parse.
This file is saved to `$CONCARDS_META`. If that environment variable doesn't
exist, then it is saved to `$HOME/.concards-meta`.
44 changes: 38 additions & 6 deletions core/card.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,14 @@ package core
import (
"bufio"
"fmt"
"regexp"
"strings"

"crypto/sha256"
)

// All the keywords that concards treats special.
const CEsc = "\\"
const CSep = "|"
const CBeg = "@>"
const CEnd = "<@"
Expand Down Expand Up @@ -93,22 +95,52 @@ func (c *Card) Len() int {
return len(c.facts)
}

func (c *Card) GetFactRaw(i int) string {
func (c *Card) getFactHelper(i int, factLogic func([]string)[]string) string {
words := []string{}
if len(c.facts) > i && 0 <= i {
return strings.Join(c.facts[i], " ")
} else {
return ""
words = factLogic(c.facts[i])
}
return strings.Join(words, " ")
}

func (c *Card) GetFactsRaw() []string {
func (c *Card) GetFactRaw(i int) string {
return c.getFactHelper(i, func(words []string) []string {
return words
})
}

// This banks on the fact that the backslash is an ASCII character at the beginning.
// If the escape character wasn't ASCII, the logic here would have to change.
func (c *Card) GetFactEsc(i int) string {
return c.getFactHelper(i, func(words []string) []string {
re := regexp.MustCompile(`^\\+`)
newWords := []string{}
for _, word := range words {
if escStr := re.ReplaceAllString(word, ""); len(escStr) < len(word) && keyWords[escStr] {
word = word[1:]
}
newWords = append(newWords, word)
}
return newWords
})
}

func (c *Card) getFactsHelper(factFunc func(*Card, int)string) []string {
facts := []string{}
for i := range c.facts {
facts = append(facts, c.GetFactRaw(i))
facts = append(facts, factFunc(c,i))
}
return facts
}

func (c *Card) GetFactsRaw() []string {
return c.getFactsHelper((*Card).GetFactRaw)
}

func (c *Card) GetFactsEsc() []string {
return c.getFactsHelper((*Card).GetFactEsc)
}

func (c *Card) GetFile() string {
return c.file
}
28 changes: 28 additions & 0 deletions core/core_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -404,3 +404,31 @@ func TestSm2Exec(t *testing.T) {
panic("Sm2 returned the wrong weight.")
}
}

func TestEsc(t *testing.T) {
raw := "in c, what is 1 \\| 2 | 3"
esc := "in c, what is 1 | 2 | 3"
rawFirst := "in c, what is 1 \\| 2"
escFirst := "in c, what is 1 | 2"

c, _ := NewCard("file1", raw)
if c.GetFactEsc(0) != escFirst {
panic("Fact not prettified/escaped.")
}

if c.GetFactRaw(0) != rawFirst {
panic("Raw fact not what it was originally.")
}

if c.GetFactRaw(-1) != "" || c.GetFactEsc(-1) != "" || c.GetFactRaw(2) != "" || c.GetFactEsc(2) != "" {
panic("Out of bounds esc and raw facts didn't work.")
}

if strings.Join(c.GetFactsRaw(), " | ") != raw {
panic("Raw facts not preserved.")
}

if strings.Join(c.GetFactsEsc(), " | ") != esc {
panic("Esc facts not preserved.")
}
}
2 changes: 1 addition & 1 deletion termboxgui/helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ func tbprintCard(c *core.Card, amount int) {
if i > 0 {
color = termbox.ColorWhite
}
_, y = tbprintwrap(0, y, color, coldef, c.GetFactRaw(i))
_, y = tbprintwrap(0, y, color, coldef, c.GetFactEsc(i))
y++
}
}
Expand Down

0 comments on commit 2395976

Please sign in to comment.