Skip to content

Commit

Permalink
RELEASE: v2.1.0
Browse files Browse the repository at this point in the history
Merge pull request #1 from tmedwards/develop
  • Loading branch information
tmedwards authored Dec 23, 2019
2 parents 57e1aa5 + e44ae8e commit 9ea2fab
Show file tree
Hide file tree
Showing 16 changed files with 124 additions and 65 deletions.
49 changes: 47 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,51 @@ See [Tweego's documentation](http://www.motoslave.net/tweego/docs/) for informat

Tweego has a Trello board, [Tweego TODO](https://trello.com/b/l5xuRzFu). Feel free to comment.

## NOTICE
## INSTALLATION

This is the initial commit to this GitHub repository, which is a migration from the old Bitbucket repository. It is based on the v2.0.0 release and is not suitable for compilation as-is due to import path differences. The first release from this repository will address that problem.
You may either download one of the precompiled binaries from [Tweego's website](http://www.motoslave.net/tweego/), which are available in both 32- and 64-bit versions for multiple operating systems, or build Tweego from source (see **BUILDING FROM SOURCE** below).

## BUILDING FROM SOURCE

If you want to build Tweego from scratch, rather than grabbing one of the precompiled binaries off of its website, then these instructions are for you.

Tweego is written in the Go programming language, so you'll need to install it, if you don't already have it. Additionally, to retrieve Go packages—like Tweego and its dependencies—from source control repositories, you'll need to install Git.

1. [Download and install the Go programming language (want ≥v1.13)](http://golang.org/doc/install)
2. [Download and install the Git source control management tool](https://git-scm.com/)

Once all the tooling is installed and set up, the next step is to fetch the Tweego source code. Open a shell to wherever you wish to store the code and run the following command:

```
git clone https://github.com/tmedwards/tweego.git
```

Next, change to the directory that the previous command created:

```
cd tweego
```

Next, fetch Tweego's dependencies via the following command:

```
go get
```

You should now have Tweego and all its dependencies downloaded, so you may now compile and install it to your `GOPATH` by running the following command:

```
go install
```

Assuming that completed with no errors, your compiled Tweego binary should be in your `GOPATH`'s `bin` directory. To run Tweego you'll need to either have added your `GOPATH` `bin` to your `PATH` environment variable—this was likely done for you automatically during the installation of Go—or copy the binary to an existing directory within your `PATH`.

Alternatively. If you just want to compile Tweego, so that you can manually copy the binary to wherever you wish, use the following command instead:

```
go build
```

Assuming that completed with no errors, your compiled Tweego binary should be in the current directory—likely named either `tweego` or `tweego.exe` depending on your OS.

Finally, see [Tweego's documentation](http://www.motoslave.net/tweego/docs/) for information on how to set it up and use it.
23 changes: 9 additions & 14 deletions config.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import (
"os"
"path/filepath"
// internal packages
"bitbucket.org/tmedwards/tweego/internal/option"
"github.com/tmedwards/tweego/internal/option"
// external packages
"github.com/paulrosania/go-charset/charset"
)
Expand Down Expand Up @@ -44,18 +44,20 @@ type config struct {
outMode outputMode // output mode

formats storyFormatsMap // map of all enumerated story formats
logFiles bool // log input files
logStats bool // log story statistics
testMode bool // enable test mode
trim bool // enable passage trimming
twee2Compat bool // enable Twee2 header extension compatibility mode
watchFiles bool // enable filesystem watching
logStats bool // log story statistics
logFiles bool // log input files
}

const (
defaultFormatID = "sugarcube-2"
defaultOutFile = "-" // <stdout>
defaultOutMode = outModeHTML
defaultStartName = "Start"
defaultTrimState = true
)

// newConfig creates a new config instance
Expand Down Expand Up @@ -97,20 +99,10 @@ func newConfig() *config {
common: common{formatID: defaultFormatID, startName: defaultStartName},
outFile: defaultOutFile,
outMode: defaultOutMode,
trim: defaultTrimState,
}

// Merge values from the environment variables.
// /*
// LEGACY
// */
// for _, env := range []string{"TWEEGO_CHARSET", "TWEEGO_FORMAT"} {
// if _, exists := os.LookupEnv(env); exists {
// log.Printf("warning: Detected obsolete environment variable %q. Please remove it from your environment.", env)
// }
// }
// /*
// END LEGACY
// */
if env := os.Getenv("TWEEGO_PATH"); env != "" {
formatDirs = append(formatDirs, filepath.SplitList(env)...)
}
Expand Down Expand Up @@ -144,6 +136,7 @@ func newConfig() *config {
options.Add("logfiles", "--log-files")
options.Add("logstats", "-l|--log-stats")
options.Add("module", "-m=s+|--module=s+")
options.Add("no_trim", "--no-trim")
options.Add("output", "-o=s|--output=s")
options.Add("start", "-s=s|--start=s")
options.Add("test", "-t|--test")
Expand Down Expand Up @@ -180,6 +173,8 @@ func newConfig() *config {
c.logStats = true
case "module":
c.modulePaths = append(c.modulePaths, val.([]string)...)
case "no_trim":
c.trim = false
case "output":
c.outFile = val.(string)
case "start":
Expand Down
4 changes: 2 additions & 2 deletions docs/core/faq-and-tips.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

This is a collection of tips, from how to avoid pitfalls to best practices.

Suggestions for new entries may be submitted by [creating a new issue](https://bitbucket.org/tmedwards/tweego/issues?status=new&status=open) at Tweego's [code repository](https://bitbucket.org/tmedwards/tweego/). **NOTE:** Acceptance of submissions ***is not*** guaranteed.
Suggestions for new entries may be submitted by [creating a new issue](https://github.com/tmedwards/tweego/issues) at Tweego's [code repository](https://github.com/tmedwards/tweego). **NOTE:** Acceptance of submissions ***is not*** guaranteed.


<!-- ***************************************************************************
Expand All @@ -14,7 +14,7 @@ Suggestions for new entries may be submitted by [creating a new issue](https://b
<span id="faq-and-tips-avoid-processing-files"></span>
## Avoid processing files

The way to avoid having Tweego process files is to not pass it the files in the first place—i.e. keep the files in question separate from the files you want Tweego to compile.
The way to avoid having Tweego process files is to not pass it the files in the first place—i.e., keep the files in question separate from the files you want Tweego to compile.

Using image files as an example, I would generally recommend a directory structure something like:

Expand Down
6 changes: 3 additions & 3 deletions docs/core/getting-started.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,8 @@ The various methods for specifying configuration settings cascade in the followi
<dd>
<p>Path(s) to search for story formats. The value should be a list of directories to search for story formats. You may specify one directory or several. The format is exactly the same as any other <em>path type</em> environment variable for your operating system.</p>
<p class="tip" role="note"><b>Tip:</b> Setting <var>TWEEGO_PATH</var> is only necessary if you intend to place your story formats outside of the directories normally searched by Tweego. See <a href="#getting-started-story-formats-search-directories">Search Directories</a> for more information.</p>
<p role="note"><b>Note:</b> To separate multiple directories within <em>path</em> variables, Unix-like operating systems use the colon, while Windows uses the semi-colon. Only relevant if you intend to specify multiple directories.</p>
<p><strong>Unix-y examples</strong></p>
<p role="note"><b>Note:</b> To separate multiple directories within <em>path</em> variables, Unix/Unix-like operating systems use the colon (<kbd>:</kbd>), while Windows uses the semi-colon (<kbd>;</kbd>). Only relevant if you intend to specify multiple directories.</p>
<p><strong>Unix/Unix-like examples</strong></p>
<p>If you wanted Tweego to search <code>/usr/local/storyformats</code>, then you'd set <code>TWEEGO_PATH</code> to:</p>
<pre><code>/usr/local/storyformats</code></pre>
<p>If you wanted Tweego to search <code>/storyformats</code> and <code>/usr/local/storyformats</code>, then you'd set <code>TWEEGO_PATH</code> to:</p>
Expand Down Expand Up @@ -106,7 +106,7 @@ When Tweego is run, it finds story formats to use by searching the following dir
4. The directories specified via the <var>TWEEGO_PATH</var> environment variable. See <a href="#getting-started-environment-variables">Environment Variables</a> for more information.

<p role="note"><b>Note:</b>
For legacy compatibility, the following directories are also checked during steps #1–3: <kbd>story-formats</kbd>, <kbd>storyFormats</kbd>, and <kbd>targets</kbd>. You are encouraged to use one of the directory names listed above instead.
For legacy compatibility, the following directories are also checked during steps #1–3: <kbd>story-formats</kbd>, <kbd>storyFormats</kbd>, and <kbd>targets</kbd>. You are <strong><em>strongly encouraged</em></strong> to use one of the directory names listed above instead.
</p>

<p class="warning" role="note"><b>Warning:</b>
Expand Down
2 changes: 1 addition & 1 deletion docs/core/special-passages-and-tags.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ The names of all special passages and tags listed herein are case sensitive, thu
<span id="special-passages-start"></span>
### `Start`

The `Start` passage will, by default, be used as the starting passage—i.e. the first normal passage displayed to the player. That behavior may be overridden via either the <var>start</var> property from the [`StoryData` passage](#special-passages-storydata) or the start command line option (<kbd>-s NAME</kbd>, <kbd>--start=NAME</kbd>).
The `Start` passage will, by default, be used as the starting passage—i.e., the first normal passage displayed to the player. That behavior may be overridden via either the <var>start</var> property from the [`StoryData` passage](#special-passages-storydata) or the start command line option (<kbd>-s NAME</kbd>, <kbd>--start=NAME</kbd>).

<p class="tip" role="note"><b>Tip:</b>
It is <strong><em>strongly recommended</em></strong> that you simply use the default starting name, <code>Start</code>, when beginning new projects.
Expand Down
4 changes: 4 additions & 0 deletions docs/core/usage.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,10 @@ Where <code>[options]</code> are mostly optional configuration flags—see [Opti
<p role="note"><b>Note:</b> Unsupported when watch mode (<kbd>-w</kbd>, <kbd>--watch</kbd>) is enabled.</p>
</dd>
<dt><kbd>-m SRC</kbd>, <kbd>--module=SRC</kbd></dt><dd>Module sources (repeatable); may consist of supported files and/or directories to recursively search for such files. Each file will be wrapped within the appropriate markup and bundled into the &lt;head&gt; element of the compiled HTML. Supported files: <code>.css</code>, <code>.js</code>, <code>.otf</code>, <code>.ttf</code>, <code>.woff</code>, <code>.woff2</code>.</dd>
<dt><kbd>--no-trim</kbd></dt><dd>
<p>Do not trim whitespace surrounding passages—i.e., whitespace preceding and trailing the actual text of the passage. By default, such whitespace is removed when processing passages.</p>
<p role="note"><b>Note:</b> It is recommended that you do not disable passage trimming.</p>
</dd>
<dt><kbd>-o FILE</kbd>, <kbd>--output=FILE</kbd></dt><dd>Name of the output file (default: <kbd>-</kbd>; i.e., <a href="https://en.wikipedia.org/wiki/Standard_streams" target="&#95;blank"><i>standard output</i></a>).</dd>
<dt><kbd>-s NAME</kbd>, <kbd>--start=NAME</kbd></dt><dd>Name of the starting passage (default: the passage set by the story data, elsewise <code>"Start"</code>).</dd>
<dt><kbd>-t</kbd>, <kbd>--test</kbd></dt><dd>Compile in test mode; only for story formats in the Twine&nbsp;2 style.</dd>
Expand Down
2 changes: 1 addition & 1 deletion docs/introduction.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,4 @@

This documentation is a reference for [Tweego](http://www.motoslave.net/tweego/), a free (gratis and libre) command line compiler for [Twine/Twee](http://twinery.org/) story formats, written in [Go](http://golang.org/).

If you believe that you've found a bug in Tweego or simply wish to make a suggestion, you may do so by [creating a new issue](https://bitbucket.org/tmedwards/tweego/issues?status=new&status=open) at its [code repository](https://bitbucket.org/tmedwards/tweego/).
If you believe that you've found a bug in Tweego or simply wish to make a suggestion, you may do so by [creating a new issue](https://github.com/tmedwards/tweego/issues) at its [code repository](https://github.com/tmedwards/tweego).
14 changes: 4 additions & 10 deletions escaping.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import (
var attrEscaper = strings.NewReplacer(
`&`, `&amp;`,
`"`, `&quot;`,
// FIXME: Keep the following? All markup we generate double quotes attribute
// QUESTION: Keep the following? All markup we generate double quotes attribute
// values, so escaping single quotes/apostrophes isn't actually necessary.
`'`, `&#39;`,
)
Expand All @@ -30,15 +30,14 @@ func attrEscapeString(s string) string {
return attrEscaper.Replace(s)
}

// Escape the minimum characters required for general HTML escaping—i.e. only
// Escape the minimum characters required for general HTML escaping—i.e., only
// the special characters (`&`, `<`, `>`, `"`, `'`).
//
// NOTE: The following exists because `html.EscapeString()` converts double
// quotes (`"`) to their decimal numeric character reference (`&#34;`) rather
// than to their entity (`&quot;`). While the behavior is entirely legal, and
// browsers will happily accept the NCRs, a not insignificant amount of JavaScript
// code does not expect it and will fail to properly unescape the NCR—expecting
// only `&quot;`.
// browsers will happily accept the NCRs, a not insignificant amount of code in
// the wild only checks for `&quot;` and will fail to properly unescape the NCR.
//
// The primary special characters (`&`, `<`, `>`, `"`) should always be
// converted to their entity forms and never to an NCR form. Saving one byte
Expand Down Expand Up @@ -101,11 +100,6 @@ func tweeEscapeBytes(s []byte) []byte {
if len(s) == 0 {
return []byte(nil)
}
// e := bytes.Replace(s, []byte("\\"), []byte("\\\\"), -1)
// e = bytes.Replace(e, []byte("["), []byte("\\["), -1)
// e = bytes.Replace(e, []byte("]"), []byte("\\]"), -1)
// e = bytes.Replace(e, []byte("{"), []byte("\\{"), -1)
// e = bytes.Replace(e, []byte("}"), []byte("\\}"), -1)

// NOTE: The slices this will be used with will be short enough that
// iterating a slice twice shouldn't be problematic. That said,
Expand Down
21 changes: 10 additions & 11 deletions formats.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import (
"path/filepath"
"strings"
// external packages
"github.com/blang/semver"
"github.com/Masterminds/semver/v3"
)

type twine2FormatJSON struct {
Expand Down Expand Up @@ -213,9 +213,9 @@ func (m storyFormatsMap) getIDFromTwine2Name(name string) string {
}

if f.name == name {
if v, err := semver.ParseTolerant(f.version); err == nil {
if found == nil || v.GT(*found) {
found = &v
if have, err := semver.NewVersion(f.version); err == nil {
if found == nil || have.GreaterThan(found) {
found = have
id = f.id
}
}
Expand All @@ -231,11 +231,10 @@ func (m storyFormatsMap) getIDFromTwine2NameAndVersion(name, version string) str
found *semver.Version
id string
)
if v, err := semver.ParseTolerant(version); err == nil {
wanted = &v
if v, err := semver.NewVersion(version); err == nil {
wanted = v
} else {
log.Printf("warning: format %q: Auto-selecting greatest version; Could not parse version %q.", name, version)
wanted = &semver.Version{Major: 0, Minor: 0, Patch: 0}
}

for _, f := range m {
Expand All @@ -244,10 +243,10 @@ func (m storyFormatsMap) getIDFromTwine2NameAndVersion(name, version string) str
}

if f.name == name {
if v, err := semver.ParseTolerant(f.version); err == nil {
if wanted.Major == 0 || v.Major == wanted.Major && v.GTE(*wanted) {
if found == nil || v.GT(*found) {
found = &v
if have, err := semver.NewVersion(f.version); err == nil {
if wanted == nil || have.Major() == wanted.Major() && have.Compare(wanted) > -1 {
if found == nil || have.GreaterThan(found) {
found = have
id = f.id
}
}
Expand Down
11 changes: 11 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
module github.com/tmedwards/tweego

go 1.13

require (
github.com/Masterminds/semver/v3 v3.0.3
github.com/paulrosania/go-charset v0.0.0-20190326053356-55c9d7a5834c
github.com/radovskyb/watcher v1.0.7
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553
golang.org/x/text v0.3.2
)
18 changes: 13 additions & 5 deletions ifid.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,15 @@ import (
"strings"
)

// IFIDs are defined in The Treaty of Babel.
// An IFID (Interactive Fiction IDentifier) uniquely identifies compiled
// projects. Most IFIDs are simply the string form of a v4 random UUID.
//
// IFIDs, in general, are defined within The Treaty of Babel.
// SEE: http://babel.ifarchive.org/
//
// Most IFIDs, and certainly those generated by Tweego, are simply the
// string form of a v4 random UUID.
// Twine ecosystem IFIDs are defined within both the Twee 3 Specification
// and Twine 2 HTML Output Specification.
// SEE: https://github.com/iftechfoundation/twine-specs/

// newIFID generates a new IFID (UUID v4).
func newIFID() (string, error) {
Expand All @@ -35,8 +39,12 @@ func newIFID() (string, error) {
// validateIFID validates ifid or returns an error.
func validateIFID(ifid string) error {
switch len(ifid) {
case 36: // xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
case 36 + 9: // UUID://xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx//
// xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
case 36:
// no-op

// UUID://xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx//
case 36 + 9:
if strings.ToUpper(ifid[:7]) != "UUID://" || ifid[43:] != "//" {
return fmt.Errorf("invalid IFID UUID://…// format")
}
Expand Down
3 changes: 3 additions & 0 deletions story.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ package main
import (
"fmt"
"log"
"strings"
)

// Twine 1 story metadata.
Expand Down Expand Up @@ -182,6 +183,8 @@ func (s *story) add(p *passage) {
log.Printf(`warning: Cannot unmarshal "StorySettings" special passage; %s.`, err.Error())
}
case "StoryTitle":
// Rebuild the passage contents to trim erroneous whitespace surrounding the title.
p.text = strings.TrimSpace(p.text)
s.name = p.text
}

Expand Down
Loading

0 comments on commit 9ea2fab

Please sign in to comment.