Compare commits
No commits in common. "61a37706dbf82ebdf5ec764543c1a03907194a2b" and "fb7eaecb42b40e1a0863fc76f5fad49d1f874120" have entirely different histories.
61a37706db
...
fb7eaecb42
8 changed files with 26 additions and 228 deletions
4
Makefile
4
Makefile
|
@ -1,5 +1,5 @@
|
|||
build: fasttyper dist
|
||||
python3 setup.py sdist bdist_wheel
|
||||
build: fasttyper
|
||||
python setup.py sdist bdist_wheel
|
||||
|
||||
push:
|
||||
twine upload dist/*
|
||||
|
|
77
README.md
77
README.md
|
@ -3,24 +3,11 @@
|
|||
|
||||
# About
|
||||
|
||||
_Fasttyper_ is minimalistic typing test based on user provided exercising text. It supports both reading from text files and stdin supporting wide range of usecases. The goal was to create it as simple as it can be, without any additional bloatware functionalities. That means that _Fasttyper_ doesn't come with build in test generator and you have to provide your own scripts generating tests. Some examples of such scripts are provided in [Usage section](#usage).
|
||||
|
||||
# Table of contents
|
||||
|
||||
- [fasttyper](#fasttyper)
|
||||
- [About](#about)
|
||||
- [Installation](#installation)
|
||||
- [Usage](#usage)
|
||||
- [Running next test and stopping application](#running-next-test-and-stopping-application)
|
||||
- [Configuring](#configuring)
|
||||
- [Usage as module, piping stuff, custom scripts etc](#usage-as-module,-piping-stuff,-custom-scripts-etc)
|
||||
- [When backspace does wierd shiet](#when-backspace-does-wierd-shiet)
|
||||
- [Hiding cursor](#hiding-cursor)
|
||||
- [Example scripts](#example-scripts)
|
||||
_Fasttyper_ is minimalistic typing test based on user provided exercising text. It supports both reading from text files and stdin supporting wide range of usecases. The goal was to create it as simple as it can be, without any additional bloatware functionalities. That means that _Fasttyper_ doesn't come with build in test generator and you have to provide your own scripts generating tests. Some examples of such scrips are providen in [Usage section](#usage).
|
||||
|
||||
# Installation
|
||||
|
||||
_Fasttyper_ is currently maintained on [PyPi](https://pypi.org/) Python Package Index. To install package simply use:
|
||||
_Fasttyper_ is currently maintained on [PyPi](https://pypi.org/) Python Package Index. To install package simpply use:
|
||||
|
||||
`python3 -m pip install fasttyper`
|
||||
|
||||
|
@ -32,7 +19,7 @@ With installation of fasttyper you should have new executable - `fasttyper`. It
|
|||
fasttyper
|
||||
```
|
||||
|
||||
from command line. There are some available options:
|
||||
from command line. There are some avalibe options:
|
||||
|
||||
```
|
||||
usage: fasttyper [-h] [--config FILE] [--unclutter-backspace] [--no-cursor] [amount] [language]
|
||||
|
@ -47,7 +34,7 @@ options:
|
|||
configuration file
|
||||
--unclutter-backspace, -b
|
||||
unclutter backspace, when it raises ctrl+backspace instead
|
||||
--no-cursor, -n disable cursors
|
||||
--no-cursor, -n disable cursos
|
||||
```
|
||||
|
||||
I personally use alias:
|
||||
|
@ -66,49 +53,7 @@ To kill application (exit) press CTRL+C.
|
|||
|
||||
# Configuring
|
||||
|
||||
Default configuration:
|
||||
|
||||
```python
|
||||
{
|
||||
"user_input_valid_color": 3,
|
||||
"user_input_invalid_color": 2,
|
||||
"reference_text_color": 9,
|
||||
"stats_template": "wpm: {stats.wpm:0.2f}, time: {stats.total_seconds:0.2f}s",
|
||||
"stats_color": 5,
|
||||
"stats_position": "top",
|
||||
"summary_datafile": "~/.cache/fasttyper/datafile.csv",
|
||||
"top_margin_percentage": 40,
|
||||
"left_margin_percentage": 35,
|
||||
"min_width": 80,
|
||||
"lines_on_screen": 3,
|
||||
"border": 1,
|
||||
"logo": " ~ FastTyper ~ ",
|
||||
"logo_color": 8,
|
||||
"resume_text": " press <Tab> to continue, <Ctrl>C to exit ",
|
||||
"resume_text_color": 9,
|
||||
"summary_template": (
|
||||
"wpm: {wpm:5.1f} | peak: {peak_wpm:5.1f}",
|
||||
"raw: {raw_wpm:5.1f} | peak: {peak_raw_wpm:5.1f}",
|
||||
"acc: {accuracy:5.1f}% | words: {correct_words}/{total_words}",
|
||||
"time: {total_seconds:5.1f}s ",
|
||||
),
|
||||
"summary_centered": True,
|
||||
"summary_color": 9,
|
||||
"summary_lines": 4,
|
||||
"summary_border": 0,
|
||||
"random_capitalization": 0,
|
||||
"random_punctuation": 0,
|
||||
"sentence_mode": False,
|
||||
"punctuation": ",.?!;:",
|
||||
"sentence_ending": ".?!",
|
||||
"amount": 25,
|
||||
"language": "english",
|
||||
"no_cursor": False,
|
||||
"unclutter_backspace": False,
|
||||
}
|
||||
```
|
||||
|
||||
Fasttyper by default looks for config file in: `$HOME/.config/fasttyper/config.json`. You can provide different location for config file with `--config` argument, for example: `--config=~/.fasttyper.json`. Config has to be a json dict. Available keys:
|
||||
Fasttyper by default looks for config file in: `$HOME/.config/fasttyper/config.json`. You can provide different location for config file with `--config` argument, for example: `--config=~/.fasttyper.json`. Config has to be a json dict. Avalibe keys:
|
||||
|
||||
- **user_input_valid_color** - integer, terminal color for valid text, by default it is 3
|
||||
- **user_input_invalid_color** - integer, terminal color for invalid text, by default it is 2
|
||||
|
@ -119,9 +64,7 @@ Fasttyper by default looks for config file in: `$HOME/.config/fasttyper/config.j
|
|||
- **left_margin_percentage** - integer, percentage of screen used for left (and right) margin, by default 10
|
||||
- **lines_on_screen** - integer, number of lines to display on screen, by default 3
|
||||
|
||||
Also there are keys that override fault parameters for CLI args, like: amount and language will override Your default settings for runner, same goes for punctuation, sentence_mode etc.
|
||||
|
||||
Example config file with all default values in available [here](https://github.com/ickyicky/fasttyper/blob/main/doc/example_config.json).
|
||||
Example config file with all default values in avalibe [here](https://github.com/ickyicky/fasttyper/blob/main/doc/example_config.json).
|
||||
|
||||
Other example config files:
|
||||
|
||||
|
@ -149,13 +92,13 @@ Program also allows user to pipe text into it. Keep in mind, it only supports sp
|
|||
|
||||
`furtune | python3 -m fasttyper`
|
||||
|
||||
or if you want to randomize words from given file with shuf on for example all dictionaries in system:
|
||||
or if you want to randomize words from given file with shuf on for example all disctionaries in system:
|
||||
|
||||
`shuf -n5 /usr/share/dict/* | python -m fasttyper`
|
||||
|
||||
You can use another similar projects set of words as well, for example to create test with 20 random words from [Monkeytype's](https://github.com/Miodec/monkeytype) english 100 dictionary use:
|
||||
|
||||
`curl -s https://raw.githubusercontent.com/monkeytypegame/monkeytype/master/frontend/static/languages/english.json | python3 -c "import sys, json; print('\n'.join(json.load(sys.stdin)['words']))" | shuf -n20 | python3 -m fasttyper`
|
||||
`curl -s https://raw.githubusercontent.com/Miodec/monkeytype/master/static/languages/english.json | python3 -c "import sys, json; print('\n'.join(json.load(sys.stdin)['words']))" | shuf -n20 | python3 -m fasttyper`
|
||||
|
||||
To exit you can either finish test, use `KeyboardInterrupt` (CTRL+C) or tap **tab**. After you finish test, there will be summary printed, use enter to exit from it.
|
||||
|
||||
|
@ -185,6 +128,6 @@ function ff() {
|
|||
```
|
||||
`ff 50 english_1k`
|
||||
|
||||
This shell function shuffles N words from cached word list, and if given word list doesn't exist it download's it. It runs in loop, but does exit from it if you exit fasttyper with CTRL+C.
|
||||
This shell function shuffles N words from cached word list, and if given word list doesnt exist it download's it. It runs in loop, but does exit from it if you exit fasttyper with CTRL+C.
|
||||
|
||||
The above script is available for download from doc folder.
|
||||
The above script is avalible for download from doc folder.
|
||||
|
|
|
@ -53,13 +53,8 @@ class Buffer:
|
|||
|
||||
def _next_word(self):
|
||||
self.current_word += 1
|
||||
|
||||
if self.current_char > 0:
|
||||
self.stats.signal_valid() # space is a char after all
|
||||
else:
|
||||
self.stats.signal_invalid() # space after empty word
|
||||
|
||||
self.current_char = 0
|
||||
self.stats.signal_valid() # space is a char after all
|
||||
|
||||
if self.current_word >= self.total_words:
|
||||
self.stats.signal_stop(True)
|
||||
|
@ -148,4 +143,4 @@ class Buffer:
|
|||
if w != self.reference_words[i]:
|
||||
count += 1
|
||||
|
||||
return count + len(self.reference_words) - len(self.user_words)
|
||||
return count
|
||||
|
|
|
@ -24,7 +24,7 @@ class RuntimeConfig:
|
|||
self.mode = mode
|
||||
|
||||
|
||||
def get_config(config_path):
|
||||
def initialize(config_path, rbuffer, backspace_debug, no_cursor, runtime_config):
|
||||
try:
|
||||
with open(os.path.expanduser(config_path)) as f:
|
||||
configmap = json.load(f)
|
||||
|
@ -32,17 +32,6 @@ def get_config(config_path):
|
|||
configmap = {}
|
||||
|
||||
config = Config(configmap)
|
||||
return config
|
||||
|
||||
|
||||
def initialize(config, rbuffer, backspace_debug, no_cursor, runtime_config):
|
||||
if isinstance(config, str):
|
||||
config = get_config(config)
|
||||
|
||||
backspace_debug = (
|
||||
backspace_debug(config) if callable(backspace_debug) else backspace_debug
|
||||
)
|
||||
no_cursor = no_cursor(config) if callable(no_cursor) else no_cursor
|
||||
|
||||
text_box = TextBox(config)
|
||||
summary = Summary(config)
|
||||
|
@ -82,21 +71,13 @@ def get_parser():
|
|||
"-b",
|
||||
action="store_true",
|
||||
help="unclutter backspace, when it raises ctrl+backspace instead",
|
||||
default=ValueFromConfig("unclutter_backspace"),
|
||||
default=False,
|
||||
)
|
||||
parser.add_argument(
|
||||
"--no-cursor",
|
||||
"-n",
|
||||
action="store_true",
|
||||
help="disable cursos",
|
||||
default=ValueFromConfig("no_cursor"),
|
||||
default=False,
|
||||
)
|
||||
return parser
|
||||
|
||||
|
||||
class ValueFromConfig:
|
||||
def __init__(self, key):
|
||||
self.key = key
|
||||
|
||||
def __call__(self, config):
|
||||
return config.get(self.key)
|
||||
|
|
|
@ -26,15 +26,6 @@ class Config:
|
|||
"summary_color": 9,
|
||||
"summary_lines": 4,
|
||||
"summary_border": 0,
|
||||
"random_capitalization": 0,
|
||||
"random_punctuation": 0,
|
||||
"sentence_mode": False,
|
||||
"punctuation": ",.?!;:",
|
||||
"sentence_ending": ".?!",
|
||||
"amount": 25,
|
||||
"language": "english",
|
||||
"no_cursor": False,
|
||||
"unclutter_backspace": False,
|
||||
}
|
||||
|
||||
def __init__(self, configmap):
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
from .cli import initialize, get_parser, RuntimeConfig, get_config, ValueFromConfig
|
||||
from random import choice, random
|
||||
from .cli import initialize, get_parser, RuntimeConfig
|
||||
from random import choice
|
||||
import os
|
||||
import requests
|
||||
import pathlib
|
||||
|
@ -33,135 +33,23 @@ def get_words(language):
|
|||
return words
|
||||
|
||||
|
||||
def generate_text(
|
||||
words,
|
||||
amount,
|
||||
capitalization_factor,
|
||||
punctuation_factor,
|
||||
sentence_mode,
|
||||
punctuation,
|
||||
sentence_ending,
|
||||
):
|
||||
chosen_words = []
|
||||
|
||||
new_sentence = True
|
||||
for _ in range(amount):
|
||||
word = choice(words)
|
||||
|
||||
if sentence_mode and new_sentence:
|
||||
word = word.capitalize()
|
||||
new_sentence = False
|
||||
elif capitalization_factor and capitalization_factor / 100 > random():
|
||||
word = word.capitalize()
|
||||
|
||||
if punctuation_factor and punctuation_factor / 100 > random():
|
||||
chosen_punctuation = choice(punctuation)
|
||||
word = "".join((word, chosen_punctuation))
|
||||
|
||||
new_sentence = word[-1] in sentence_ending
|
||||
chosen_words.append(word)
|
||||
|
||||
return " ".join(chosen_words)
|
||||
|
||||
|
||||
def runner():
|
||||
parser = get_parser()
|
||||
|
||||
parser.add_argument(
|
||||
"amount",
|
||||
type=int,
|
||||
default=ValueFromConfig("amount"),
|
||||
help="Amount of words",
|
||||
nargs="?",
|
||||
"amount", type=int, default=25, help="Amount of words", nargs="?"
|
||||
)
|
||||
parser.add_argument(
|
||||
"language",
|
||||
type=str,
|
||||
default=ValueFromConfig("language"),
|
||||
help="Language",
|
||||
nargs="?",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-rc",
|
||||
"--random-capitalization",
|
||||
type=int,
|
||||
default=ValueFromConfig("random_capitalization"),
|
||||
help="Percent of randomally capitalized words",
|
||||
action="store",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-rp",
|
||||
"--random-punctuation",
|
||||
type=int,
|
||||
default=ValueFromConfig("random_capitalization"),
|
||||
help="Percent of words that will have randomally appender punctuation at the end",
|
||||
action="store",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-sm",
|
||||
"--sentence-mode",
|
||||
default=ValueFromConfig("sentence_mode"),
|
||||
help="Forces uppercase after sentence ending characters like dot or question mark and at the beggining of text",
|
||||
action="store_true",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--punctuation",
|
||||
type=str,
|
||||
default=ValueFromConfig("punctuation"),
|
||||
help="List of all punctuation characters",
|
||||
action="store",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--sentence-ending",
|
||||
type=str,
|
||||
default=ValueFromConfig("sentence_ending"),
|
||||
help="List of all punctuation characters that end sentence",
|
||||
action="store",
|
||||
"language", type=str, default="english", help="Language", nargs="?"
|
||||
)
|
||||
|
||||
args = parser.parse_args()
|
||||
config = get_config(args.config)
|
||||
|
||||
random_punctuation = (
|
||||
args.random_punctuation(config)
|
||||
if callable(args.random_punctuation)
|
||||
else args.random_punctuation
|
||||
)
|
||||
random_capitalization = (
|
||||
args.random_capitalization(config)
|
||||
if callable(args.random_capitalization)
|
||||
else args.random_capitalization
|
||||
)
|
||||
sentence_mode = (
|
||||
args.sentence_mode(config)
|
||||
if callable(args.sentence_mode)
|
||||
else args.sentence_mode
|
||||
)
|
||||
punctuation = (
|
||||
args.punctuation(config) if callable(args.punctuation) else args.punctuation
|
||||
)
|
||||
sentence_ending = (
|
||||
args.sentence_ending(config)
|
||||
if callable(args.sentence_ending)
|
||||
else args.sentence_ending
|
||||
)
|
||||
amount = args.amount(config) if callable(args.amount) else args.amount
|
||||
language = args.language(config) if callable(args.language) else args.language
|
||||
|
||||
words = get_words(language)
|
||||
words = get_words(args.language)
|
||||
|
||||
while True:
|
||||
rbuffer = generate_text(
|
||||
words,
|
||||
amount,
|
||||
random_capitalization,
|
||||
random_punctuation,
|
||||
sentence_mode,
|
||||
punctuation,
|
||||
sentence_ending,
|
||||
)
|
||||
rbuffer = " ".join([choice(words) for _ in range(args.amount)])
|
||||
initialize(
|
||||
config,
|
||||
args.config,
|
||||
rbuffer,
|
||||
args.unclutter_backspace,
|
||||
args.no_cursor,
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
[bumpversion]
|
||||
current_version = 2.4.2
|
||||
current_version = 2.3.0
|
||||
|
||||
[wheel]
|
||||
universal = 1
|
||||
|
|
2
setup.py
2
setup.py
|
@ -9,7 +9,7 @@ with open("requirements.txt", "r", encoding="utf-8") as fh:
|
|||
|
||||
setup(
|
||||
name="fasttyper",
|
||||
version="2.4.2",
|
||||
version="2.3.0",
|
||||
author="Piotr Domanski",
|
||||
author_email="pi.domanski@gmail.com",
|
||||
description="Minimalistic typing exercise",
|
||||
|
|
Loading…
Reference in a new issue