Skip to main content

tweep/
lib.rs

1//! Tweep is a parser for the Twee 3 interactive fiction format
2//!
3//! # What is Twee?
4//! Twee is "a text format for marking up the source code of Twine stories." It
5//! is an alternate way to produce interactive fiction stories for the [Twine 2]
6//! platform, using plain text files instead of a graphical environment. The
7//! specification for Twee 3, supported by tweep, can be found [here]
8//!
9//! # Goals
10//! The goal of tweep is to provide a fully standards-compliant Twee 3 parser
11//! that provides helpful warning and error messages for bad practices and
12//! common mistakes, which can be used as a backend for a compiler as well as
13//! other novel applications of the Twee 3 format.
14//!
15//! # What it's not
16//! * A compiler - while a corresponding compiler front end is in the works,
17//!   this is not it. tweep only produces rust objects, not html
18//! * A Twee v1 or v2 parser - currently, there are no plans for supporting any
19//!   version of the Twee specification other than Twee 3
20//!
21//! # Getting started
22//! To use tweep in your Rust project, simply add the following to your
23//! Cargo.toml:
24//!
25//! ```toml
26//! [dependencies]
27//! tweep = "0.2"
28//! ```
29//!
30//! For basic parsing, the main entry point into tweep is through the [`Story`]
31//! struct, which provides utility methods for parsing out a complete story from
32//! a `String` or a `Path` representing a file or directory. When given a
33//! directory, tweep will parse all files ending in `.tw` or `.twee` and merge
34//! them into a single output story. For more advanced parsing, such as if the
35//! tags or metadata attached to a special passage is needed, [`StoryPassages`]
36//! provides the same interface, but provides [`Passage`] objects in places
37//! where usually unnecessary information is stripped out.
38//!
39//! # Examples
40//! ```
41//! use tweep::Story;
42//! let input = r#":: StoryTitle
43//!RustDoc Sample Story
44//!
45//!:: StoryData
46//!{
47//!  "ifid": "D674C58C-DEFA-4F70-B7A2-27742230C0FC",
48//!  "format": "SugarCube",
49//!  "format-version": "2.28.2",
50//!  "start": "My Starting Passage",
51//!  "tag-colors": {
52//!    "tag1": "green",
53//!    "tag2": "red",
54//!    "tag3": "blue"
55//!  },
56//!  "zoom": 0.25
57//!}
58//!
59//!:: My Starting Passage [ tag1 tag2 ]
60//!This is the starting passage, specified by the start attribute of StoryData.
61//!Alternately, we could remove that attribute and rename the passage to Start.
62//!
63//!It has tags and links to:
64//!  [[Another passage]]
65//!  [[Here too!|Another passage]]
66//!  [[A third passage<-And a different passage]]
67//!
68//!:: Another passage {"position":"600,400","size":"100,200"}
69//!This passage has some metadata attached to it
70//!
71//!:: A third passage [tag3] { "position": "400,600" }
72//!This passage has both tags and metadata. The size attribute of the metadata
73//!isn't overridden, so it will be set to the default value.
74//!"#.to_string();
75//!
76//!// Parse the input into an Output<Result<Story, ErrorList>>
77//!let out = Story::from_string(input);
78//!assert!(!out.has_warnings());
79//!
80//!// Move the Result out of the Output
81//!let (res, _) = out.take();
82//!assert!(res.is_ok());
83//!
84//!// Get the Story object
85//!let story = res.ok().unwrap();
86//!
87//!// StoryTitle and StoryData contents are parsed into special fields
88//!assert_eq!(story.title.unwrap(), "RustDoc Sample Story");
89//!assert_eq!(story.data.unwrap().ifid, "D674C58C-DEFA-4F70-B7A2-27742230C0FC");
90//!
91//!// Other passages are parsed into a map, keyed by the passage name
92//!assert_eq!(story.passages["My Starting Passage"].tags(), &vec!["tag1", "tag2"]);
93//!let metadata = story.passages["A third passage"].metadata();
94//!assert_eq!(metadata["size"], "100,100");
95//!assert_eq!(metadata["position"], "400,600");
96//! ```
97//!
98//! [Twine 2]: https://twinery.org/
99//! [here]: https://github.com/iftechfoundation/twine-specs/blob/master/twee-3-specification.md
100//! [`Story`]: struct.Story.html
101//! [`StoryPassages`]: struct.StoryPassages.html
102//! [`Passage`]: struct.Passage.html
103
104#![warn(missing_docs)]
105#![warn(missing_doc_code_examples)]
106
107/// The output context type for [`Error`]s and [`Warning`]s. If the feature
108/// `full-context` is enabled, this will be a [`FullContext`] which will include
109/// the ability to retrieve the associated source Twee v3 code. Otherwise, it
110/// will be a [`PartialContext`] which will only include the file name and a
111/// starting location for the error/warning
112///
113/// [`Error`]: struct.Error.html
114/// [`Warning`]: struct.Warning.html
115/// [`FullContext`]: struct.FullContext.html
116/// [`PartialContext`]: struct.PartialContext.html
117#[cfg(feature = "full-context")]
118pub type Context = FullContext;
119
120/// The output context type for [`Error`]s and [`Warning`]s. If the feature
121/// `full-context` is enabled, this will be a [`FullContext`] which will include
122/// the ability to retrieve the associated source Twee v3 code. Otherwise, it
123/// will be a [`PartialContext`] which will only include the file name and a
124/// starting location for the error/warning
125///
126/// [`Error`]: struct.Error.html
127/// [`Warning`]: struct.Warning.html
128/// [`FullContext`]: struct.FullContext.html
129/// [`PartialContext`]: struct.PartialContext.html
130#[cfg(not(feature = "full-context"))]
131pub type Context = PartialContext;
132
133mod context;
134pub use context::Position;
135pub use context::PositionKind;
136pub use context::FullContext;
137pub use context::PartialContext;
138
139mod issues;
140pub use issues::Error;
141pub use issues::ErrorList;
142pub use issues::ErrorKind;
143pub use issues::Warning;
144pub use issues::WarningKind;
145
146mod output;
147pub use output::Output;
148
149mod passages;
150pub use passages::Passage;
151pub use passages::PassageContent;
152pub use passages::PassageHeader;
153pub use passages::ScriptContent;
154pub use passages::StoryData;
155pub use passages::StoryTitle;
156pub use passages::StylesheetContent;
157pub use passages::TwineContent;
158pub use passages::TwineLink;
159pub use passages::TwinePassage;
160
161mod stories;
162#[cfg(feature = "full-context")]
163pub use stories::CodeMap;
164#[cfg(feature = "full-context")]
165pub use stories::ContextErrorList;
166pub use stories::Story;
167pub use stories::StoryPassages;