This commit is contained in:
Amolith 2019-11-18 14:32:35 -05:00
parent 2e14654474
commit b11bbf9599
Signed by: Amolith
GPG Key ID: CA3EFC40662C19BA
21 changed files with 355 additions and 41 deletions

283
bin/speedread Executable file
View File

@ -0,0 +1,283 @@
#!/usr/bin/env perl
#
# speedread: A simple terminal-based open source spritz-alike
#
# Show input text as a per-word RSVP (rapid serial visual presentation)
# aligned on optimal reading points. This kind of input mode allows
# reading text at a much more rapid pace than usual as the eye can
# stay fixed on a single place.
#
# (c) Petr Baudis <pasky@ucw.cz> 2014
# MIT licence
#
# Usage: cat file.txt | speedread [-w WORDSPERMINUTE] [-r RESUMEPOINT] [-m]
#
# The default of 250 words per minut is very timid, designed so that
# you get used to this. Be sure to try cranking this up, 500wpm
# should still be fairly easy to follow even for beginners.
#
# speedread can join short words together if you specify the -m switch.
# It did not work well for pasky so far, though.
#
# speedread is slightly interactive, with these controls accepted:
#
# [ - slow down by 10%
# ] - speed up by 10%
# space - pause (and show the last two lines)
use warnings;
use strict;
use autodie;
use v5.14;
my $wpm = 250;
my $resume = 0;
my $multiword = 0;
use utf8;
binmode(STDIN, ":encoding(UTF-8)");
binmode(STDOUT, ":encoding(UTF-8)");
use Term::ANSIColor;
use POSIX qw(ceil floor);
use Time::HiRes qw(time sleep gettimeofday tv_interval);
use Getopt::Long;
GetOptions("wpm|w=i" => \$wpm,
"resume|r=i" => \$resume,
"multiword|m" => \$multiword);
my $wordtime = 0.9; # relative to wpm
my $lentime = 0.04; # * sqrt(length $word), relative to wpm
my $commatime = 2; # relative to wpm
my $fstoptime = 3; # relative to wpm
my $multitime = 1.2; # relative to wpm
my $firsttime = 0.2; # [s]
my $ORPloc = 0.35;
my $ORPmax = 0.2;
my $ORPvisualpos = 20;
my $cursorpos = 64;
my $paused = 0;
my $current_word;
my $current_orp;
my $next_word_time = 0;
my $next_input_time = 0;
my $skipped = 0;
my @lastlines;
my $tty = rawinput->new();
$| = 1;
my $wordcounter = 0;
my $lettercounter = 0;
my $t0 = [gettimeofday];
sub print_stats {
my $elapsed = tv_interval($t0, [gettimeofday]);
my $truewpm = $wordcounter / $elapsed * 60;
printf("\n %.2fs, %d words, %d letters, %s%.2f%s true wpm\n",
$elapsed, $wordcounter, $lettercounter,
color('bold green'), $truewpm, color('reset'));
}
$SIG{INT} = sub {
print_stats;
my $resume_word = $wordcounter + $resume;
say " To resume from this point run with argument -r $resume_word";
exit;
};
main();
# ORP: Optical Recognition Point (the red-colored alignment pilot),
# the way Spritz probably does it.
sub find_ORP {
my ($word, $ORPloc) = @_;
return 4 if (length($word) > 13);
return (0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3)[length($word)];
}
sub show_guide {
# Top visual guide
say(" "x$ORPvisualpos . color('red') . "v" . color('reset') . "\033[K");
}
sub show_word {
my ($word, $i) = @_;
my $pivotch = substr($word, $i, 1);
$pivotch = "·" if $pivotch eq ' ';
print("\r\033[K"
. " " x ($ORPvisualpos - $i)
. color("bold")
. substr($word, 0, $i)
. color("red")
. $pivotch
. color("reset")
. color("bold")
. substr($word, $i+1)
. color("reset")
. " " x ($cursorpos - (($ORPvisualpos - $i) + length($word)))
. "$wpm wpm"
. ($paused ? " ".color("yellow")."PAUSED".color("reset") : ""));
}
sub word_time {
my ($word) = @_;
my $time = $wordtime;
if ($word =~ /[\.\?]\W*$/) {
$time = $fstoptime;
} elsif ($word =~ /[:;,]\W*$/) {
$time = $commatime;
} elsif ($word =~ / /) {
$time = $multitime;
}
$time += sqrt(length($word)) * $lentime;
$time *= 60 / $wpm;
# Give user some time to focus on the first word, even with high wpm.
$time = $firsttime if ($wordcounter == 0 and $time < $firsttime);
return $time;
}
sub print_context {
my ($wn) = @_;
# One line up and to its beginning
print "\r\033[K\033[A\033[K";
# First line of context
say $lastlines[1] if $lastlines[1];
# In second line of context, highlight our word
my $line0 = $lastlines[0];
my $c0 = color('yellow');
my $c1 = color('reset');
$line0 =~ s/^((?:.*?(?:-|\s)+){$wn})(.*?)(-|\s)/$1$c0$2$c1$3/;
say $line0;
}
sub process_keys {
my ($word, $i, $wn) = @_;
while ($tty->key_pressed()) {
my $ch = $tty->getch();
if ($ch eq '[') {
$wpm = int($wpm * 0.9);
} elsif ($ch eq ']') {
$wpm = int($wpm * 1.1);
} elsif ($ch eq ' ') {
$paused = not $paused;
if ($paused) {
# Print context.
print_context($wn);
show_guide();
show_word($word, $i);
}
else {
$next_word_time = time();
}
}
}
}
sub main {
show_guide();
$next_word_time = time();
$next_input_time = time();
while (<>) {
chomp;
unshift @lastlines, $_;
pop @lastlines if @lastlines > 2;
my (@words) = grep { /./ } split /(?:-|\s)+/;
if ($multiword) {
# Join adjecent short words
for (my $i = 0; $i < $#words - 1; $i++) {
if (length($words[$i]) <= 3 and length($words[$i+1]) <= 3) {
$words[$i] .= ' ' . $words[$i+1];
splice(@words, $i+1, 1);
}
}
}
my $wn = 0;
while (scalar(@words) > 0) {
if ($skipped < $resume) {
$skipped++;
shift @words;
next;
}
my $current_time = time();
if ($next_word_time <= $current_time and !$paused) {
$current_word = shift @words;
$current_orp = find_ORP($current_word, $ORPloc);
$next_word_time += word_time($current_word);
$wordcounter++;
$lettercounter += length($current_word);
$wn++;
}
if ($next_input_time <= $current_time) {
process_keys($current_word, $current_orp, $wn);
$next_input_time += 0.05; # checking for input 20 times / second seems to give a reasonably responsive UI
}
# redrawing the word on each "frame" gives a more responsive UI
# (we don't have to wait for the word to change to display changed stats like wpm)
show_word($current_word, $current_orp);
my $sleep_time = ($next_word_time < $next_input_time and !$paused) ? $next_word_time-$current_time : $next_input_time-$current_time;
sleep($sleep_time) if ($sleep_time > 0);
}
}
print_stats();
sleep(1);
}
package rawinput;
# An ad-hoc interface to interactive terminal input. Term::Screen *should*
# have been a natural choice here, unfortunately it is fixated at reading
# from stdin instead of /dev/tty. Tough.
sub new {
my $class = shift;
my $self;
open $self, '/dev/tty';
bless $self, $class;
stty('min 1', '-icanon', '-echo');
return $self;
}
sub DESTROY {
stty('cooked', 'echo');
}
sub stty {
my $self = shift;
eval { system('stty', $^O eq 'darwin' ? '-f' : '-F', '/dev/tty', @_); };
}
sub key_pressed {
my $self = shift;
my $readfields = '';
vec($readfields, fileno($self), 1) = 1;
my $ready = 0;
eval { $ready = select($readfields, undef, undef, 0); };
return $ready;
}
sub getch {
my $self = shift;
getc($self);
}

BIN
fonts/.fonts/Cabin-Bold.ttf Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -132,10 +132,10 @@
id="rect"
style="fill:blue;"
usecurrent="1"
width="7.97975"
height="141.497"
width="120.208"
height="33.335"
rx="0"
ry="3.25" />
ry="1.18252" />
<eventcontext
id="3dbox"
style="stroke:none;stroke-linejoin:round;"
@ -171,16 +171,17 @@
end="0"
start="0"
usecurrent="1"
rx="131.32"
ry="131.32" />
rx="48.1646"
ry="48.1646" />
<eventcontext
id="star"
magnitude="5"
magnitude="6"
style="fill:yellow;"
usecurrent="1"
proportion="0.5"
rounded="0"
randomized="0" />
randomized="0"
isflatsided="1" />
<eventcontext
id="spiral"
style="fill:none;stroke:black"
@ -335,10 +336,11 @@
font_sample="AaBbCcIiPpQq12369$€¢?.;/()"
show_sample_in_list="1"
style="fill:black;fill-opacity:1;stroke:none;font-family:sans-serif;font-style:normal;font-weight:normal;font-size:40px;line-height:1.25;letter-spacing:0px;word-spacing:0px"
selcue="1">
selcue="1"
align_mode="1">
<group
id="lineheight"
display_unit="0" />
display_unit="0"
id="lineheight" />
</eventcontext>
<eventcontext
id="nodes"
@ -424,12 +426,12 @@
offset="0"
offsetunits="cm" />
<group
id="measure"
fontsize="10"
precision="2"
scale="100"
unit="px"
offset="5"
unit="px" />
scale="100"
precision="2"
fontsize="10"
id="measure" />
</group>
<group
id="palette">
@ -576,15 +578,27 @@
page="0"
x="0"
y="0"
w="354"
h="427"
w="451"
h="485"
visible="1"
state="2"
placement="1" />
placement="5" />
<group
id="filtereffects" />
<group
id="textandfont" />
id="textandfont"
panel_size="1"
panel_ratio="100"
panel_mode="1"
panel_wrap="0"
panel_border="0"
x="0"
y="0"
w="451"
h="485"
visible="1"
state="2"
placement="5" />
<group
id="transformation"
applyseparately="0" />
@ -595,14 +609,14 @@
panel_mode="1"
panel_wrap="0"
panel_border="0"
align-to="0"
align-to="4"
x="0"
y="0"
w="354"
h="412"
w="451"
h="485"
visible="1"
state="2"
placement="2" />
placement="5" />
<group
id="xml" />
<group
@ -621,8 +635,8 @@
panel_mode="1"
panel_wrap="0"
panel_border="0"
x="950"
y="210"
x="821"
y="466"
w="623"
h="652"
visible="0"
@ -656,17 +670,17 @@
panel_border="0"
x="0"
y="0"
w="356"
h="487"
w="451"
h="485"
visible="1"
state="2"
placement="2">
placement="5">
<group
id="exportarea"
value="page" />
value="drawing" />
<group
id="defaultxdpi"
value="128.21" />
value="304.76" />
</group>
<group
id="save_as"
@ -688,7 +702,7 @@
<group
id="import"
enable_preview="1"
path="/home/amolith/repos/nixnet/assets/svgs/"
path="/home/amolith/Pictures/Me/Web/"
ask="1"
link="embed"
scale="optimizeQuality"
@ -728,7 +742,7 @@
panel_mode="1"
panel_wrap="0"
panel_border="0"
x="663"
x="623"
y="0"
w="585"
h="398"
@ -747,6 +761,20 @@
on-focus="1.0"
on-blur="0.50"
animate-time="100" />
<group
id="symbols"
panel_size="1"
panel_ratio="100"
panel_mode="1"
panel_wrap="0"
panel_border="0"
x="0"
y="0"
w="451"
h="485"
visible="1"
state="2"
placement="5" />
</group>
<group
id="printing">
@ -1035,14 +1063,15 @@
</group>
<group
id="extensions"
org.inkscape.input.gdkpixbuf.png.scale="optimizeQuality" />
org.inkscape.input.gdkpixbuf.png.scale="optimizeQuality"
org.inkscape.input.gdkpixbuf.jpg.scale="optimizeQuality" />
<group
id="desktop"
style="line-height:1.25;fill:#ffffff;fill-opacity:1;-inkscape-font-specification:'Open Sans';font-family:'Open Sans';font-weight:normal;font-style:normal;font-stretch:normal;font-variant:normal">
style="line-height:1.25;fill:#ffffff;fill-opacity:1;-inkscape-font-specification:Comfortaa;font-family:Comfortaa;font-weight:normal;font-style:normal;font-stretch:normal;font-variant:normal;font-size:16.11599986px;text-anchor:middle;text-align:center;writing-mode:lr;font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;stroke:none;stroke-opacity:1;stroke-width:5;stroke-miterlimit:4;stroke-dasharray:none">
<group
width="663"
width="1336"
height="698"
x="688"
x="15"
y="35"
fullscreen="0"
id="geometry"

View File

@ -1 +1 @@
756
1103

View File

@ -1,9 +1,9 @@
sw_volume: 64
audio_device_state:1:pulse audio
audio_device_state:1:my_fifo
state: play
current: 830
time: 3.858000
state: pause
current: 713
time: 332.959000
random: 0
repeat: 0
single: 0

View File

@ -2,4 +2,4 @@ set-option -g prefix C-q
set-window-option -g mode-keys vi
bind-key -t vi-copy 'v' begin-selection
bind-key -t vi-copy 'y' copy-selection
set -g mouse on
set -g mouse off

View File

@ -10,6 +10,7 @@ export PATH="$HOME/.cargo/bin:$PATH"
export PATH="$PATH:$HOME/.local/bin"
export PATH="$HOME/.gem/ruby/2.6.0/bin:$PATH"
export PATH="$HOME/.rbenv/bin:$PATH"
export PATH="$HOME/go/bin:$PATH"
export GEM_HOME="$HOME/gems"
export CHROOT="$HOME/chroot"
export EDITOR="nvim"
@ -57,6 +58,7 @@ alias b="bluetoothctl"
alias vim="nvim"
alias v="nvim"
alias ssh="ssh -Y"
alias gen="pwgen -s 20 1 | xclip -selection clipboard"
unset zle_bracketed_paste
source /usr/share/zsh/plugins/zsh-syntax-highlighting/zsh-syntax-highlighting.zsh