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

#![warn(missing_docs)]
#![warn(missing_doc_code_examples)]

/// The output context type for [`Error`]s and [`Warning`]s. If the feature
/// `full-context` is enabled, this will be a [`FullContext`] which will include
/// the ability to retrieve the associated source Twee v3 code. Otherwise, it
/// will be a [`PartialContext`] which will only include the file name and a
/// starting location for the error/warning
///
/// [`Error`]: struct.Error.html
/// [`Warning`]: struct.Warning.html
/// [`FullContext`]: struct.FullContext.html
/// [`PartialContext`]: struct.PartialContext.html
#[cfg(feature = "full-context")]
pub type Context = FullContext;

/// The output context type for [`Error`]s and [`Warning`]s. If the feature
/// `full-context` is enabled, this will be a [`FullContext`] which will include
/// the ability to retrieve the associated source Twee v3 code. Otherwise, it
/// will be a [`PartialContext`] which will only include the file name and a
/// starting location for the error/warning
///
/// [`Error`]: struct.Error.html
/// [`Warning`]: struct.Warning.html
/// [`FullContext`]: struct.FullContext.html
/// [`PartialContext`]: struct.PartialContext.html
#[cfg(not(feature = "full-context"))]
pub type Context = PartialContext;

mod context;
pub use context::Position;
pub use context::PositionKind;
pub use context::FullContext;
pub use context::PartialContext;

mod issues;
pub use issues::Error;
pub use issues::ErrorList;
pub use issues::ErrorKind;
pub use issues::Warning;
pub use issues::WarningKind;

mod output;
pub use output::Output;

mod passages;
pub use passages::Passage;
pub use passages::PassageContent;
pub use passages::PassageHeader;
pub use passages::ScriptContent;
pub use passages::StoryData;
pub use passages::StoryTitle;
pub use passages::StylesheetContent;
pub use passages::TwineContent;
pub use passages::TwineLink;
pub use passages::TwinePassage;

mod stories;
#[cfg(feature = "full-context")]
pub use stories::CodeMap;
#[cfg(feature = "full-context")]
pub use stories::ContextErrorList;
pub use stories::Story;
pub use stories::StoryPassages;