Ui features (#6)

* fix #3: added h ui command to toggle ui
* fix #4: added -N flag to disable colors
* fixed styling of line numbers (-n)
* fix #5 add usage section
* add pkg/epub module readme
* add license terms to all file headers
* fixed usage printing
* added basic unit tests
* run the tests only on linux due to the use of base64 utitlity
This commit is contained in:
T.v.Dein
2025-10-17 14:10:45 +02:00
committed by GitHub
parent b50c6acff0
commit 08f470e0d5
17 changed files with 2034 additions and 31 deletions

View File

@@ -1,3 +1,19 @@
/*
Copyright © 2025 Thomas von Dein
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package cmd
import (

View File

@@ -1,3 +1,19 @@
/*
Copyright © 2025 Thomas von Dein
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package cmd
import (
@@ -16,8 +32,10 @@ import (
)
const (
Version string = `v0.0.3`
Usage string = `Usage epuppy [options] <epub file>
Version string = `v0.0.4`
Usage string = `This is epuppy, a terminal ui ebook viewer.
Usage: epuppy [options] <epub file>
Options:
-D --dark enable dark mode
@@ -26,24 +44,26 @@ Options:
-c --config <file> use config <file>
-t --txt dump readable content to STDOUT
-x --xml dump source xml to STDOUT
-N --no-color disable colors (or use $NO_COLOR env var)
-d --debug enable debugging
-h --help show help message
-v --version show program version`
)
type Config struct {
Showversion bool `koanf:"version"` // -v
Debug bool `koanf:"debug"` // -d
StoreProgress bool `koanf:"store-progress"` // -s
Darkmode bool `koanf:"dark"` // -D
LineNumbers bool `koanf:"line-numbers"` // -n
Dump bool `koanf:"txt"` // -t
XML bool `koanf:"xml"` // -x
Config string `koanf:"config"` // -c
ColorDark ColorSetting `koanf:"colordark"` // comes from config file only
ColorLight ColorSetting `koanf:"colorlight"` // comes from config file only
Colors Colors // generated from user config file or internal defaults, respects dark mode
Showversion bool `koanf:"version"` // -v
Debug bool `koanf:"debug"` // -d
StoreProgress bool `koanf:"store-progress"` // -s
Darkmode bool `koanf:"dark"` // -D
LineNumbers bool `koanf:"line-numbers"` // -n
Dump bool `koanf:"txt"` // -t
XML bool `koanf:"xml"` // -x
NoColor bool `koanf:"no-color"` // -n
Config string `koanf:"config"` // -c
ColorDark ColorSetting `koanf:"colordark"` // comes from config file only
ColorLight ColorSetting `koanf:"colorlight"` // comes from config file only
ShowHelp bool `koanf:"help"`
Colors Colors // generated from user config file or internal defaults, respects dark mode
Document string
InitialProgress int // lines
}
@@ -58,7 +78,6 @@ func InitConfig(output io.Writer) (*Config, error) {
if err != nil {
log.Fatalf("failed to print to output: %s", err)
}
os.Exit(0)
}
// parse commandline flags
@@ -69,6 +88,8 @@ func InitConfig(output io.Writer) (*Config, error) {
flagset.BoolP("line-numbers", "n", false, "add line numbers")
flagset.BoolP("txt", "t", false, "dump readable content to STDOUT")
flagset.BoolP("xml", "x", false, "dump xml to STDOUT")
flagset.BoolP("no-color", "N", false, "disable colors")
flagset.BoolP("help", "h", false, "show help")
flagset.StringP("config", "c", "", "read config from file")
if err := flagset.Parse(os.Args[1:]); err != nil {
@@ -117,8 +138,9 @@ func InitConfig(output io.Writer) (*Config, error) {
if len(flagset.Args()) > 0 {
conf.Document = flagset.Args()[0]
} else {
if !conf.Showversion {
if !conf.Showversion && !conf.ShowHelp {
flagset.Usage()
os.Exit(1)
}
}
@@ -140,6 +162,11 @@ func InitConfig(output io.Writer) (*Config, error) {
},
conf)
// disable colors if requested by command line
if conf.NoColor {
_ = os.Setenv("NO_COLOR", "1")
}
return conf, nil
}

View File

@@ -1,3 +1,19 @@
/*
Copyright © 2025 Thomas von Dein
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package cmd
// pager setup using bubbletea
@@ -46,18 +62,22 @@ type Meta struct {
}
type keyMap struct {
Up key.Binding
Down key.Binding
Left key.Binding
Right key.Binding
Help key.Binding
Quit key.Binding
Up key.Binding
Down key.Binding
Left key.Binding
Right key.Binding
Help key.Binding
Quit key.Binding
ToggleUI key.Binding
Pad key.Binding
}
func (k keyMap) FullHelp() [][]key.Binding {
return [][]key.Binding{
{k.Up, k.Down, k.Left, k.Right}, // first column
{k.Help, k.Quit}, // second column
// every item is one column
{k.Up, k.Down, k.Left, k.Right},
{k.Pad}, // fake key, we use it as spacing between columns
{k.Help, k.Quit, k.ToggleUI},
}
}
@@ -66,6 +86,10 @@ func (k keyMap) ShortHelp() []key.Binding {
}
var keys = keyMap{
Pad: key.NewBinding(
key.WithKeys("__"),
key.WithHelp(" ", ""),
),
Up: key.NewBinding(
key.WithKeys("up", "k"),
key.WithHelp("↑", "move up"),
@@ -75,11 +99,11 @@ var keys = keyMap{
key.WithHelp("↓", "move down"),
),
Left: key.NewBinding(
key.WithKeys("left", "h"),
key.WithKeys("left"),
key.WithHelp("←", "decrease text width"),
),
Right: key.NewBinding(
key.WithKeys("right", "l"),
key.WithKeys("right"),
key.WithHelp("→", "increase text width"),
),
Help: key.NewBinding(
@@ -90,6 +114,10 @@ var keys = keyMap{
key.WithKeys("q", "esc", "ctrl+c"),
key.WithHelp("q", "quit"),
),
ToggleUI: key.NewBinding(
key.WithKeys("h"),
key.WithHelp("h", "toggle ui"),
),
}
type Doc struct {
@@ -101,6 +129,7 @@ type Doc struct {
lastwidth int
margin int
marginMod bool
hideUi bool
meta *Meta
config *Config
@@ -135,6 +164,8 @@ func (m Doc) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
m.margin -= MarginStep
m.marginMod = true
}
case key.Matches(msg, m.keys.ToggleUI):
m.hideUi = !m.hideUi
}
case tea.WindowSizeMsg:
@@ -212,6 +243,10 @@ func (m Doc) View() string {
helpView = "\n" + m.help.View(m.keys)
}
if m.hideUi {
return fmt.Sprintf("%s\n%s", m.viewport.View(), helpView)
}
return fmt.Sprintf("%s\n%s\n%s%s", m.headerView(), m.viewport.View(), m.footerView(), helpView)
}
@@ -253,7 +288,7 @@ func Pager(conf *Config, title, message string) (int, error) {
if conf.LineNumbers {
catn := ""
for idx, line := range strings.Split(message, "\n") {
catn += fmt.Sprintf("%d: %s\n", idx, line)
catn += fmt.Sprintf("%4d: %s\n", idx, line)
}
message = catn
}

View File

@@ -1,3 +1,19 @@
/*
Copyright © 2025 Thomas von Dein
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package cmd
import (
@@ -27,6 +43,15 @@ func Execute(output io.Writer) int {
return 0
}
if conf.ShowHelp {
_, err := fmt.Fprintln(output, Usage)
if err != nil {
return Die(fmt.Errorf("failed to print to output: %s", err))
}
return 0
}
if conf.StoreProgress {
progress, err := GetProgress(conf)
if err == nil {

View File

@@ -1,3 +1,19 @@
/*
Copyright © 2025 Thomas von Dein
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package cmd
import (

View File

@@ -1,3 +1,19 @@
/*
Copyright © 2025 Thomas von Dein
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package cmd
import (