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

@@ -21,9 +21,29 @@ jobs:
- name: build - name: build
run: go build run: go build
test:
strategy:
matrix:
version: [1.24.9]
os: [ubuntu-latest]
name: Test
runs-on: ${{ matrix.os }}
steps:
- name: Set up Go ${{ matrix.os }}
uses: actions/setup-go@v6
with:
go-version: '${{ matrix.version }}'
id: go
- name: checkout
uses: actions/checkout@v5
- name: test
run: go test -cover ./...
golangci: golangci:
name: lint name: Lintercheck
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/setup-go@v6 - uses: actions/setup-go@v6

View File

@@ -27,6 +27,66 @@ long run.
- Showing the help - Showing the help
![Screenshot](https://github.com/TLINDEN/epuppy/blob/main/.github/assets/help.png) ![Screenshot](https://github.com/TLINDEN/epuppy/blob/main/.github/assets/help.png)
## Usage
To read an ebook, just give a filename as argument to `epuppy`.
Add the option `-s` to store and use a previously stored reading
progress.
Sometimes you may be unhappy with the colors. Depending on your
terminal style you can enable dark mode with `-D`, light mode is the
default. You can also configure custom colors in a config file in
`$HOME/.config/epuppy/confit.toml`:
```toml
# color setting for dark mode
colordark = {
body = "#ffffff",
title = "#7cfc00",
chapter = "#ffff00"
}
# color setting for light mode
colorlight = {
body = "#000000",
title = "#8470ff",
chapter = "#00008b"
}
# always use dark mode
dark = true
```
There are also cases where your current terminal just doesn't have the
capabilites for this stuff. I stumbled upon such a case during an SSH
session from my Android phone to a FreeBSD server. For this you can
either just disable colors with `-N` or by setting the environment
variable `$NO_COLOR` to 1. Or you can just dump the text of the ebook
and pipe it to some pager, e.g.:
```default
epuppy -t someebook.epub | less
```
There are also a couple of debug options etc, all options:
```default
Usage epuppy [options] <epub file>
Options:
-D --dark enable dark mode
-s --store-progress remember reading position
-n --line-numbers add line numbers
-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
```
## Installation ## Installation
The tool does not have any dependencies. Just download the binary for The tool does not have any dependencies. Just download the binary for
@@ -83,4 +143,4 @@ version 3.
# Author # Author
Copyleft (c) 2024 Thomas von Dein Copyleft (c) 2025 Thomas von Dein

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 package cmd
import ( 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 package cmd
import ( import (
@@ -16,8 +32,10 @@ import (
) )
const ( const (
Version string = `v0.0.3` Version string = `v0.0.4`
Usage string = `Usage epuppy [options] <epub file> Usage string = `This is epuppy, a terminal ui ebook viewer.
Usage: epuppy [options] <epub file>
Options: Options:
-D --dark enable dark mode -D --dark enable dark mode
@@ -26,24 +44,26 @@ Options:
-c --config <file> use config <file> -c --config <file> use config <file>
-t --txt dump readable content to STDOUT -t --txt dump readable content to STDOUT
-x --xml dump source xml to STDOUT -x --xml dump source xml to STDOUT
-N --no-color disable colors (or use $NO_COLOR env var)
-d --debug enable debugging -d --debug enable debugging
-h --help show help message -h --help show help message
-v --version show program version` -v --version show program version`
) )
type Config struct { type Config struct {
Showversion bool `koanf:"version"` // -v Showversion bool `koanf:"version"` // -v
Debug bool `koanf:"debug"` // -d Debug bool `koanf:"debug"` // -d
StoreProgress bool `koanf:"store-progress"` // -s StoreProgress bool `koanf:"store-progress"` // -s
Darkmode bool `koanf:"dark"` // -D Darkmode bool `koanf:"dark"` // -D
LineNumbers bool `koanf:"line-numbers"` // -n LineNumbers bool `koanf:"line-numbers"` // -n
Dump bool `koanf:"txt"` // -t Dump bool `koanf:"txt"` // -t
XML bool `koanf:"xml"` // -x XML bool `koanf:"xml"` // -x
Config string `koanf:"config"` // -c NoColor bool `koanf:"no-color"` // -n
ColorDark ColorSetting `koanf:"colordark"` // comes from config file only Config string `koanf:"config"` // -c
ColorLight ColorSetting `koanf:"colorlight"` // comes from config file only 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 ShowHelp bool `koanf:"help"`
Colors Colors // generated from user config file or internal defaults, respects dark mode
Document string Document string
InitialProgress int // lines InitialProgress int // lines
} }
@@ -58,7 +78,6 @@ func InitConfig(output io.Writer) (*Config, error) {
if err != nil { if err != nil {
log.Fatalf("failed to print to output: %s", err) log.Fatalf("failed to print to output: %s", err)
} }
os.Exit(0)
} }
// parse commandline flags // 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("line-numbers", "n", false, "add line numbers")
flagset.BoolP("txt", "t", false, "dump readable content to STDOUT") flagset.BoolP("txt", "t", false, "dump readable content to STDOUT")
flagset.BoolP("xml", "x", false, "dump xml 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") flagset.StringP("config", "c", "", "read config from file")
if err := flagset.Parse(os.Args[1:]); err != nil { 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 { if len(flagset.Args()) > 0 {
conf.Document = flagset.Args()[0] conf.Document = flagset.Args()[0]
} else { } else {
if !conf.Showversion { if !conf.Showversion && !conf.ShowHelp {
flagset.Usage() flagset.Usage()
os.Exit(1)
} }
} }
@@ -140,6 +162,11 @@ func InitConfig(output io.Writer) (*Config, error) {
}, },
conf) conf)
// disable colors if requested by command line
if conf.NoColor {
_ = os.Setenv("NO_COLOR", "1")
}
return conf, nil 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 package cmd
// pager setup using bubbletea // pager setup using bubbletea
@@ -46,18 +62,22 @@ type Meta struct {
} }
type keyMap struct { type keyMap struct {
Up key.Binding Up key.Binding
Down key.Binding Down key.Binding
Left key.Binding Left key.Binding
Right key.Binding Right key.Binding
Help key.Binding Help key.Binding
Quit key.Binding Quit key.Binding
ToggleUI key.Binding
Pad key.Binding
} }
func (k keyMap) FullHelp() [][]key.Binding { func (k keyMap) FullHelp() [][]key.Binding {
return [][]key.Binding{ return [][]key.Binding{
{k.Up, k.Down, k.Left, k.Right}, // first column // every item is one column
{k.Help, k.Quit}, // second 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{ var keys = keyMap{
Pad: key.NewBinding(
key.WithKeys("__"),
key.WithHelp(" ", ""),
),
Up: key.NewBinding( Up: key.NewBinding(
key.WithKeys("up", "k"), key.WithKeys("up", "k"),
key.WithHelp("↑", "move up"), key.WithHelp("↑", "move up"),
@@ -75,11 +99,11 @@ var keys = keyMap{
key.WithHelp("↓", "move down"), key.WithHelp("↓", "move down"),
), ),
Left: key.NewBinding( Left: key.NewBinding(
key.WithKeys("left", "h"), key.WithKeys("left"),
key.WithHelp("←", "decrease text width"), key.WithHelp("←", "decrease text width"),
), ),
Right: key.NewBinding( Right: key.NewBinding(
key.WithKeys("right", "l"), key.WithKeys("right"),
key.WithHelp("→", "increase text width"), key.WithHelp("→", "increase text width"),
), ),
Help: key.NewBinding( Help: key.NewBinding(
@@ -90,6 +114,10 @@ var keys = keyMap{
key.WithKeys("q", "esc", "ctrl+c"), key.WithKeys("q", "esc", "ctrl+c"),
key.WithHelp("q", "quit"), key.WithHelp("q", "quit"),
), ),
ToggleUI: key.NewBinding(
key.WithKeys("h"),
key.WithHelp("h", "toggle ui"),
),
} }
type Doc struct { type Doc struct {
@@ -101,6 +129,7 @@ type Doc struct {
lastwidth int lastwidth int
margin int margin int
marginMod bool marginMod bool
hideUi bool
meta *Meta meta *Meta
config *Config config *Config
@@ -135,6 +164,8 @@ func (m Doc) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
m.margin -= MarginStep m.margin -= MarginStep
m.marginMod = true m.marginMod = true
} }
case key.Matches(msg, m.keys.ToggleUI):
m.hideUi = !m.hideUi
} }
case tea.WindowSizeMsg: case tea.WindowSizeMsg:
@@ -212,6 +243,10 @@ func (m Doc) View() string {
helpView = "\n" + m.help.View(m.keys) 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) 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 { if conf.LineNumbers {
catn := "" catn := ""
for idx, line := range strings.Split(message, "\n") { 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 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 package cmd
import ( import (
@@ -27,6 +43,15 @@ func Execute(output io.Writer) int {
return 0 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 { if conf.StoreProgress {
progress, err := GetProgress(conf) progress, err := GetProgress(conf)
if err == nil { 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 package cmd
import ( 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 package cmd
import ( import (

4
go.mod
View File

@@ -48,5 +48,7 @@ require (
github.com/mitchellh/copystructure v1.2.0 // indirect github.com/mitchellh/copystructure v1.2.0 // indirect
github.com/mitchellh/reflectwalk v1.0.2 // indirect github.com/mitchellh/reflectwalk v1.0.2 // indirect
github.com/pelletier/go-toml v1.9.5 // indirect github.com/pelletier/go-toml v1.9.5 // indirect
golang.org/x/net v0.33.0 // indirect github.com/rogpeppe/go-internal v1.14.1 // indirect
golang.org/x/net v0.44.0 // indirect
golang.org/x/tools v0.37.0 // indirect
) )

6
go.sum
View File

@@ -74,6 +74,8 @@ github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJ
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ=
github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc=
github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk= github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk=
github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
@@ -104,6 +106,8 @@ golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I= golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I=
golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4= golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4=
golang.org/x/net v0.44.0 h1:evd8IRDyfNBMBTTY5XRF1vaZlD+EmWx6x8PkhR04H/I=
golang.org/x/net v0.44.0/go.mod h1:ECOoLqd5U3Lhyeyo/QDCEVQ4sNgYsqvCZ722XogGieY=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@@ -154,6 +158,8 @@ golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
golang.org/x/tools v0.37.0 h1:DVSRzp7FwePZW356yEAChSdNcQo6Nsp+fex1SUW09lE=
golang.org/x/tools v0.37.0/go.mod h1:MBN5QPQtLMHVdvsbtarmTNukZDdgwdwlO5qGacAzF0w=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

16
main.go
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 main package main
import ( import (

38
main_test.go Normal file
View File

@@ -0,0 +1,38 @@
/*
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 main
import (
"testing"
"github.com/rogpeppe/go-internal/testscript"
)
// see https://bitfieldconsulting.com/golang/test-scripts
func TestMain(m *testing.M) {
testscript.Main(m, map[string]func(){
"epuppy": main,
})
}
func TestEpuppy(t *testing.T) {
testscript.Run(t, testscript.Params{
Dir: "t",
})
}

View File

@@ -1,6 +1,6 @@
#!/bin/bash #!/bin/bash
# Copyright © 2024 Thomas von Dein # Copyright © 2025 Thomas von Dein
# This program is free software: you can redistribute it and/or modify # 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 # it under the terms of the GNU General Public License as published by

21
pkg/epub/README.md Normal file
View File

@@ -0,0 +1,21 @@
# epub module
This is a modified version of the [epub
module](https://github.com/kapmahc/epub/). I fixed a couple of issues
and I added code to retrieve the actual epub content, which the
original module doesn't implement. Since the last update on that
module was 9 years ago (as I write this), it doesn't make sense to
send a PR. And it also makes no sense to me to publish it separately.
# ORIGINAL README
## epub
A pure go implementation of epub file format.
### Documents
- <http://idpf.org/epub>
- <http://www.cnblogs.com/Alex80/p/5127104.html>
- <http://www.cnblogs.com/diligenceday/p/4999315.html>

BIN
pkg/epub/test.epub Normal file

Binary file not shown.

7
t/basic.txtar Normal file
View File

@@ -0,0 +1,7 @@
# no args shall fail
! exec epuppy
# help
exec epuppy -h
stdout 'This is epuppy'

1698
t/read-parse.txtar Normal file

File diff suppressed because it is too large Load Diff