From 7a7d79b57def9fd0ba040bca64f6436ce10613a5 Mon Sep 17 00:00:00 2001 From: kts Date: Thu, 27 Nov 2014 16:05:50 -0800 Subject: [PATCH] Initial commit of kettext. Contains mostly complete implementation of kettext. --- .kettext.pl.swp | Bin 0 -> 36864 bytes .kettext_rules.ktx.swp | Bin 0 -> 24576 bytes TODO.ktx | 22 + documentation/kettext_define.ktx | 14 + documentation/kettext_history.ktx | 14 + documentation/kettext_rules.jp.ktx | 215 ++++++++++ documentation/kettext_rules.ktx | 217 ++++++++++ kettext.pl | 422 +++++++++++++++++++ test/all.ktx | 124 ++++++ test/code.ktx | 3 + test/example.ktx | 45 ++ test/header.ktx | 9 + test/header_test.ktx | 23 ++ test/list.ktx | 15 + test/lists.ktx | 31 ++ test/paragraph.ktx | 57 +++ test/proclib.ktx | 633 +++++++++++++++++++++++++++++ test/spacer.ktx | 7 + test/test.ktx | 132 ++++++ test/text.ktx | 4 + 20 files changed, 1987 insertions(+) create mode 100644 .kettext.pl.swp create mode 100644 .kettext_rules.ktx.swp create mode 100644 TODO.ktx create mode 100644 documentation/kettext_define.ktx create mode 100644 documentation/kettext_history.ktx create mode 100644 documentation/kettext_rules.jp.ktx create mode 100644 documentation/kettext_rules.ktx create mode 100755 kettext.pl create mode 100644 test/all.ktx create mode 100644 test/code.ktx create mode 100644 test/example.ktx create mode 100644 test/header.ktx create mode 100644 test/header_test.ktx create mode 100644 test/list.ktx create mode 100644 test/lists.ktx create mode 100644 test/paragraph.ktx create mode 100644 test/proclib.ktx create mode 100644 test/spacer.ktx create mode 100644 test/test.ktx create mode 100644 test/text.ktx diff --git a/.kettext.pl.swp b/.kettext.pl.swp new file mode 100644 index 0000000000000000000000000000000000000000..b5d72b4001f3cfee21eb341529ef5fd289e2fd02 GIT binary patch literal 36864 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 literal 0 HcmV?d00001 diff --git a/TODO.ktx b/TODO.ktx new file mode 100644 index 0000000..9cc91c4 --- /dev/null +++ b/TODO.ktx @@ -0,0 +1,22 @@ +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +TODO +```````````````````````````````` + 1. Sections - flag that enables placing div(?)s after a header and until a header of the same size is found (or end of elements). + 2. Table of Contents generation - flag that enables the generation of a table of contents via headers. Builds into a list(?) + 3. alternative tags, for img, audio, video, etc. (!!!) + * it would be cool to make it able to just take URLs for popular sites and figure out the rest. This is unlikely, however, but it would be neat (and give us an advantage over other markup languages!). + * maybe like [[video:somefile.flv]] or [[video:http://youtube.com/...]] ? + * [[img:my_image.png]] ? + * maybe some sort of convertTo::*::parseEmbed that has hooks? + * convertTo::*::embed_handlers => ( + tag => "video", + handler => &function + ); + * Reformat code and place it in its own "class"/"context", e.g., "kettext::" + * @elements kettext::parseFile + * Create some sort of interface for conversion + * kettext::convertTo::HTML ? + * kettext::convertTo::ktx + * kettext::convertTo::Markdown + * kettext::convertTo::textile + * writing should print to stdout OR to outbound file if marked. diff --git a/documentation/kettext_define.ktx b/documentation/kettext_define.ktx new file mode 100644 index 0000000..1915af4 --- /dev/null +++ b/documentation/kettext_define.ktx @@ -0,0 +1,14 @@ +.imply(header.depth=1) +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +kettext... +```````````````````````````````` + * **is for the design-inclined programmer** + * **is easy to write with** + * **looks nice in a terminal** + * **formats wonderfully to HTML5** + * **provides support for modern video and audio embedding** + * **supports writing out to other popular markup formats such as //markdown// or //textile//** + * **is a growing language that is not afraid of change** + * **contributions and enhancements are //promoted//** + +Most of all, kettext provides a general syntax that strives to keep your markup __clean__ and easy to maintain. diff --git a/documentation/kettext_history.ktx b/documentation/kettext_history.ktx new file mode 100644 index 0000000..4082887 --- /dev/null +++ b/documentation/kettext_history.ktx @@ -0,0 +1,14 @@ +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +A Brief History of kettext +```````````````````````````````` +From a linguistics perspective, kettext is the formal definition of a more loose internal documentation/note format I've used for many of my projects. However, the reason it came to be a formal syntax is a bit more involved. + +When I released the procedural generation library, [[proclib]].href(../proclib/), I wrote some brief documentation for it on its [[itch.io page]].href(http://kts_kettek.itch.io/proclib). Due to preferring self-hosting, I wanted to have the same documentation under my webserver as was on the itch.io page. However, this led to some formatting issues, as itch.io's HTML source output tended towards breakage when modifying lists and similar - it also meant that the original source would be itch.io. + +From this, I figured I would convert the documentation into a markup language and convert from that to both itch.io and my own page. However, after trying various markup languages, such as markdown and textile, I found them to be quite limiting when wanting to implement some HTML-centric options (such as class, name, and similar). + +As a result, I decided to format the source text into the documentation/note format that I had become accustomed to using. This meant that I would have to write a parser and converter -- something I did not initially feel inclined to do due to other projects. + +However, given that I use this private format for internal documentation and my own notes, it seemed to be the logical thing to do. Furthermore, it gave me an excuse to pick up Perl(((after over 5 years!))) and actually learn to use regular expressions. + +What was born from this was a codified version of my internal documentation format -- //kettext// -- and the accompanying parser/converter, **kettext.pl**. diff --git a/documentation/kettext_rules.jp.ktx b/documentation/kettext_rules.jp.ktx new file mode 100644 index 0000000..80ac4ed --- /dev/null +++ b/documentation/kettext_rules.jp.ktx @@ -0,0 +1,215 @@ +.imply(header.ids) +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +kettextのルール +```````````````````````````````` +ソースコードが偉大な学習法だから、ソースコードの後にフォーマットされた例あります。 + +セクションの説明: + * 要素のタイプ + * 説明 + * 特別なルール + * 例とソース +,,,,,,,,,,,,,,,,,,,,,,,, +フォーマットルール +```````````````````````` +,,,,,,,,,,,,,,,, +.imply +```````````````` +Every kettext document may have an //optional// line that defines **implied** rules for the generation of the document. + +This line must start at the end and/or the beginning of the document and contains the rules inside the ".imply()" formatter. An example would be: + + # .imply(header.ids,header.depth=2) + +**Possible .imply values:** + * //header.ids// -- create ids for every header from header text. Replaces spaces with underscores. + * //header.depth// -- set the starting depth of headers. Defaults to 0. + * //header.reverse// -- sets smaller headers to be considered as greater, e.g., "==== header ====" is greater than "====== header ======" + * //version.hide// -- embeds the version of kettext used to create the document in a hidden format. Otherwise is added as a footer. + * //version.none// -- completely removes version information from the output. + +Other rules can be implied via the command-line. These override the kettext file's imply rules when a conflict arises. Example: + + #kettext.pl my_file.ktx --header.ids --header.depth=2 +,,,,,,,,,,,,,,,, +Element formatters +```````````````` +Elements, which may be paragraphs, lists, headers, and most any other classification of text, can possess various formatters. Formatters are options that are applied to an element and effect the conversion output. The prominent usage is within the HTML converter, wherein formatters are convertered to HTML tag (@@) options. + +The placement of formatters varies between the elements, but the general appearance is: + + # .some_option(some_value).other_option(other_value) +,,,,,,,,,,,,,,,,,,,,,,,, +Font styling and anchors +```````````````````````` +Font may be styled in any of the following manners: + + # I am **bold**, but I can also be //italic// + # + # I am also ((small))! + # + # I may also contain ``code``! + # + # I can also be an [[anchor]], but you need an [[href]].href(#Font_styling_and_anchors)! + +I am **bold**, but I can also be //italic// + +I am also ((small))! + +I may also contain ``code``! + +I can also be an [[anchor]], but you need an [[href]].href(#Font_styling_and_anchors)! + +---- +Styled text may have formatters appended to them as well: + + # **bold**.class(super_bold) + +**bold**.class(super_bold) + +---- +If using an HTML formatter, you can pass CSS styling directly: + + # **bold**.style(font-size:16pt;color:#AA2299;) + +**bold**.style(font-size:16pt;color:#AA2299;) + + # [[link]].href(http://kettek.exoss.net).style(border:1px solid red) + +[[link]].href(http://kettek.exoss.net).style(border:1px solid red) +,,,,,,,,,,,,,,,,,,,,,,,, +Headers +```````````````````````` +A header is some prominently formatted text that precedes a larger section of text and acts as a demarker. Headers are sized in order of precedence, with larger visual headers being considered the parent of smaller headers contained within. + +Due to kettext's flexible design, header sizing is calculated after document parsing. For HTML conversion, the header with the largest lead will be "<h1>", with smaller leads increasing in number thereafter. If **header.reverse** is set, this behavior is reversed, and the header with the smallest lead is set to "<h1>", with larger leads increasing from there. + +In kettext, there are two styles of headers, big and small. These styles may be mixed, although big headers have a size precedence over small, so results will be varied. + +Header contents may have //text styling// applied. + +,,,,,,,,,,,,,,,, +Small Headers +```````````````` +Small headers are similar to other markup languages' headers, but are more flexible due to kettek's inherent design. + + #==== //My Header// ===== +==== //My Header// ==== +---- +Headers may use any character to signify their lead or close: + + #~~~~ My Tilde'd Header ~~~~ +~~~~ My Tilde'd Header ~~~~ + +---- +Headers do not require a close: + + #==== My Header Without Close +==== My Header Without Close + +---- +If the close-style is used, the close must match the lead: + + #==== Header Without Close ---- +==== Header Without Close ---- +---- +Formatters are applied at the end of the header content: + + #==== Header With Formatter .class(alt_header) ==== +==== Header With Formatter .class(alt_header) ==== + + #==== Header With Formatter .class(alt_header) +==== Header With Formatter .class(alt_header) + +,,,,,,,,,,,,,,,, +Big Headers +```````````````` +Big headers are headers that span 3 lines and may have a more stylized visual. They are also the preferred header style of the author. + + #,,,,,,,,,,,, + #Big Header + #```````````` +,,,,,,,,,,,, +Big Header +```````````` +---- +Big headers can use any character for the head and the lead. They are not required to match. + #____________ + #//Big Header// + #------------ +____________ +//Big Header// +------------ +---- +Formatters are placed at the end of the content line: + #,,,,,,,,,,,, + #Big Header .class(big_alt) + #```````````` + +,,,,,,,,,,,, +Big Header .class(big_alt) +```````````` +,,,,,,,,,,,,,,,,,,,,,,,, +Text Blocks +```````````````````````` +Text blocks are a larger collection of text that may or may not span multiple lines. kettext uses 4 unique text blocks: **paragraph**, **preformatted**, **code**, and **block quote**. +,,,,,,,,,,,,,,,, +Paragraph +```````````````` +A paragraph is a section of text that spans one or more lines. A section of text will continue as a single paragraph until an empty line is found. + # This is a multi-line paragraph + # that continues to here. + # + # This is a **second paragraph**, note the above empty line. + +This is a multi-line paragraph +that continues to here. + +This is a **second paragraph**, note the above empty line. +---- +Formatters may be applied by having a separate formatter line at the start of the paragraph: + # .class(alt_paragraph) + # This is a formatted paragraph. +,,,,,,,,,,,,,,,, +Preformatted +```````````````` +Preformatted text is a section of text that is unprocessed by kettext and put within its own paragraph-like section. Every line must be indented by a tab, 2 spaces, or 4 spaces. + # .class(alt_pre) + # This is preformatted text and + # it can span multiple lines. + # //font styling// is **ignored**! + # + # and will continue if an indented, but otherwise empty, line is found. + + .class(alt_pre) + This is preformatted text and + it can span multiple lines. + //font styling// is **ignored**! + + and will continue if an indented, but otherwise empty, line is found. +,,,,,,,,,,,,,,,, +Code +```````````````` +Code text is a section of text that is also unprocessed by kettext and follows the same general rules as preformatted. Every line must be indented by a tab, 2 spaces, or 4 spaces, and followed by a '#'. + # #.class(alt_code) + # #This is code text and + # #it can span multiple lines as well. + # #//font styling// is **ignored**! + # # + # #it also continues if an indented empty line is provided. + + #.class(alt_code) + #This is code text and + #it can span multiple lines as well. + #//font styling// is **ignored**! + # + #it also continues if an indented empty line is provided. +,,,,,,,,,,,,,,,, +Blockquotes +```````````````` +Blockquotes are unprocessed sections of quoted text. They are signified by the first character of a line being a '>': + #>.class(alt_block) + #> This is a block quote. If blockquote.parse is not set, //font styling// is **ignored**! + +>.class(alt_block) +> This is a block quote. If blockquote.parse is not set, //font styling// is **ignored**! diff --git a/documentation/kettext_rules.ktx b/documentation/kettext_rules.ktx new file mode 100644 index 0000000..20aff5f --- /dev/null +++ b/documentation/kettext_rules.ktx @@ -0,0 +1,217 @@ +.imply(header.ids) +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +kettext Rules +```````````````````````````````` +As is the case with most any syntax, the best way to learn is to view the end product and the syntax used to generate it. + +However, so as to avoid creating examples of every syntax permutation possible, this section is organized in the following manner: + * Type of Element + * General description + * Special rules + * Example(s) and Source(s) +,,,,,,,,,,,,,,,,,,,,,,,, +Formatting rules +```````````````````````` +,,,,,,,,,,,,,,,, +.imply +```````````````` + # .imply(header.ids,header.depth=2) + +imply rules influence the parsing and conversion of markup on a document-wide level. Through these rules, you can change header sizing behaviors, output tables of contents, create logical sections of converted elements for use in visual styling, and much more. + +This line must start at the end and/or the beginning of the document and contains the rules inside the ".imply()" formatter. An example would be: + +**Possible .imply values:** + * //header.ids// -- create ids for every header from header text. Replaces spaces with underscores. + * //header.depth// -- set the starting depth of headers. Defaults to 0. + * //header.reverse// -- sets smaller headers to be considered as greater, e.g., "==== header ====" is greater than "====== header ======" + * //version.hide// -- embeds the version of kettext used to create the document in a hidden format. Otherwise is added as a footer. + * //version.none// -- completely removes version information from the output. + +Other rules can be implied via the command-line. These override the kettext file's imply rules when a conflict arises. Example: + + # kettext.pl my_file.ktx --header.ids --header.depth=2 +,,,,,,,,,,,,,,,, +Element formatters +```````````````` + # **boldface**.id(alt_bold) + +Formatters are a set of options that influence the outputted **element**'s styles. These are used by a **Convertor** engine to create particular visual styling. For the [[HTML Convertor]].href(#HTML_Converter), this means applying a class, a style, or any other supported option for a given element tag. Don't clutter your markup source with HTML when you can apply it in a more generalized and clean manner. + +The placement of formatters varies between the elements, but the general syntax is: + + # .some_option(some_value).other_option(other_value) +,,,,,,,,,,,,,,,,,,,,,,,, +Font styling and anchors +```````````````````````` +Font may be styled in any of the following manners: + + # I am **bold**, but I can also be //italic// + # + # I am also ((small))! + # + # I may also contain ``code``! + # + # I can also be an [[anchor]], but you need an [[href]].href(#Font_styling_and_anchors)! + +I am **bold**, but I can also be //italic// + +I am also ((small))! + +I may also contain ``code``! + +I can also be an [[anchor]], but you need an [[href]].href(#Font_styling_and_anchors)! + +---- +Styled text may have formatters appended to them: + + # **bold**.class(super_bold) + +**bold**.class(super_bold) + +---- +If using an HTML convertor, you can pass CSS styling directly: + + # **bold**.style(font-size:16pt;color:#AA2299;) + +**bold**.style(font-size:16pt;color:#AA2299;) + + # [[link]].href(http://kettek.exoss.net).style(border:1px solid red) + +[[link]].href(http://kettek.exoss.net).style(border:1px solid red) +,,,,,,,,,,,,,,,,,,,,,,,, +Headers +```````````````````````` +A header is some prominently formatted text that precedes a larger section of text and acts as a demarker. Headers are sized in order of precedence, with larger visual headers being considered the parent of smaller headers contained within. + +Due to kettext's flexible design, header sizing is calculated after document parsing. For HTML conversion, the header with the largest lead will be "<h1>", with smaller leads increasing in number thereafter. If **header.reverse** is set, this behavior is reversed, and the header with the smallest lead is set to "<h1>", with larger leads increasing from there. + +In kettext, there are two styles of headers, big and small. These styles may be mixed, although big headers have a size precedence over small, so results will be varied. + +Header contents may have //text styling// applied. + +,,,,,,,,,,,,,,,, +Small Headers +```````````````` +Small headers are similar to other markup languages' headers, but are more flexible due to kettext's inherent design. + + #==== //My Header// ===== +==== //My Header// ==== +---- +Headers may use any character to signify their lead or close: + + #~~~~ My Tilde'd Header ~~~~ +~~~~ My Tilde'd Header ~~~~ + +---- +Headers do not require a close: + + #==== My Header Without Close +==== My Header Without Close + +---- +If the close-style is used, the close must match the lead: + + #==== Header Without Close ---- +==== Header Without Close ---- +---- +Formatters are applied at the end of the header content: + + #==== Header With Formatter .class(alt_header) ==== +==== Header With Formatter .class(alt_header) ==== + + #==== Header With Formatter .class(alt_header) +==== Header With Formatter .class(alt_header) + +,,,,,,,,,,,,,,,, +Big Headers +```````````````` +Big headers are headers that span 3 lines and may have a more stylized visual. They are also the preferred header style of the author. + + #,,,,,,,,,,,, + #Big Header + #```````````` +,,,,,,,,,,,, +Big Header +```````````` +---- +Big headers can use any character for the head and the lead. They are not required to match. + #____________ + #//Big Header// + #------------ +____________ +//Big Header// +------------ +---- +Formatters are placed at the end of the content line: + #,,,,,,,,,,,, + #Big Header .class(big_alt) + #```````````` + +,,,,,,,,,,,, +Big Header .class(big_alt) +```````````` +,,,,,,,,,,,,,,,,,,,,,,,, +Text Blocks +```````````````````````` +Text blocks are a larger collection of text that may or may not span multiple lines. kettext uses 4 unique text blocks: **paragraph**, **preformatted**, **code**, and **block quote**. +,,,,,,,,,,,,,,,, +Paragraph +```````````````` +A paragraph is a section of text that spans one or more lines. A section of text will continue as a single paragraph until an empty line is found. + # This is a multi-line paragraph + # that continues to here. + # + # This is a **second paragraph**, note the above empty line. + +This is a multi-line paragraph +that continues to here. + +This is a **second paragraph**, note the above empty line. +---- +Formatters may be applied by having a separate formatter line at the start of the paragraph: + # .class(alt_paragraph) + # This is a formatted paragraph. +,,,,,,,,,,,,,,,, +Preformatted +```````````````` +Preformatted text is a section of text that is unprocessed by kettext and put within its own paragraph-like section. Every line must be indented by a tab, 2 spaces, or 4 spaces. + # .class(alt_pre) + # This is preformatted text and + # it can span multiple lines. + # //font styling// is **ignored**! + # + # and will continue if an indented, but otherwise empty, line is found. + + .class(alt_pre) + This is preformatted text and + it can span multiple lines. + //font styling// is **ignored**! + + and will continue if an indented, but otherwise empty, line is found. +,,,,,,,,,,,,,,,, +Code +```````````````` +Code text is a section of text that is also unprocessed by kettext and follows the same general rules as preformatted. Every line must be indented by a tab, 2 spaces, or 4 spaces, and followed by a '#'. + # #.class(alt_code) + # #This is code text and + # #it can span multiple lines as well. + # #//font styling// is **ignored**! + # # + # #it also continues if an indented empty line is provided. + + #.class(alt_code) + #This is code text and + #it can span multiple lines as well. + #//font styling// is **ignored**! + # + #it also continues if an indented empty line is provided. +,,,,,,,,,,,,,,,, +Blockquotes +```````````````` +Blockquotes are unprocessed sections of quoted text. They are signified by the first character of a line being a '>': + #>.class(alt_block) + #> This is a block quote. If blockquote.parse is not set, //font styling// is **ignored**! + +>.class(alt_block) +> This is a block quote. If blockquote.parse is not set, //font styling// is **ignored**! diff --git a/kettext.pl b/kettext.pl new file mode 100755 index 0000000..75e6a3c --- /dev/null +++ b/kettext.pl @@ -0,0 +1,422 @@ +#!/usr/bin/perl +use strict; +use warnings; +# +my %cmd_settings = (); +# arg check / usage +if ($#ARGV+1 == 0) { + printf "Usage: kettext.pl file_name.ktx\n"; + exit; +} +my $file_name; + +for (my $arg_i = 0; $arg_i < $#ARGV+1; $arg_i++) { + if ($ARGV[$arg_i] =~ m/^-(-|)(.*)/) { + if ($2 =~ m/^(h(elp|))$/) { + printf "Usage: kettext.pl file_name.ktx\n"; + exit; + } else { + if ($2 =~ m/^(.[^\=]*)(\=|)(.*|)/) { + $cmd_settings{$1} = (length($3) ? $3 : 1); + } + } + } else { + $file_name = $ARGV[$arg_i]; + } +} +# create file handler +binmode STDOUT, ":utf8"; +use utf8; +open(my $fh, '<:encoding(UTF-8)', $file_name) + or die "ERR: could not open file '$file_name' $!"; +# create our parse "enum" +use constant { + PARSE_HEADER_BIG => 1 << 1, + PARSE_HEADER_SMALL => 1 << 2, + PARSE_HEADER_BOTH => 1 << 1 | 1 << 2, +}; +use constant { + TYPE_HEADER => 1, + TYPE_PARAGRAPH => 2, + TYPE_PRE => 3, + TYPE_RULE => 4, + TYPE_SPACER => 5, + TYPE_BREAK => 6, + TYPE_CODE => 7, + TYPE_BLOCKQUOTE => 8, + TYPE_LIST => 9 +}; +# create our general data +my %sections; +my @elements = (); # our list of ALL distinct elements +my %block = (); # some block of data, such as paragraph, pre, etc. +my %settings = (); +# main logic: line reading +chomp(my @lines = <$fh>); close($fh); +for (my $i = 0; $i <= $#lines; $i++) { + # check for imply rules on first line + if ($i == 0 || $i == $#lines) { + if ($lines[$i] =~ m/^(\..*\)(\s|))(.*)/) { + if ($1 =~ m/^.*\((.*)\)/) { + my @options = split(',', $1); + foreach my $opt (@options) { + my @value = split('=', $opt); + $settings{$value[0]} = ($value[1] ? $value[1] : 1); + } + } + next; + } + } + # 1. check for indent-related lines (pre, code, list, etc.) + if ($lines[$i] =~ m/^(\t|\s\s|\s\s\s\s)(.)(.*)/) { + # code + if ($2 eq '#') { + if (!%block) { + if ($3 =~ m/^([^\s]*)(\..*\)(\s|))(.*)/) { + %block = (type => TYPE_CODE, text => $3, opts => parseOptions($2)); + } else { + %block = (type => TYPE_CODE, text => $3); + } + } else { + if ($block{"type"} != TYPE_CODE) { + push @elements, {%block}; + if ($3 =~ m/^([^\s*])(\..*\)(\s|))(.*)/) { + %block = (type => TYPE_CODE, text => $3, opts => parseOptions($2)); + } else { + %block = (type => TYPE_CODE, text => $3); + } + } else { + $block{'text'} .= "\n".$3; + } + } + # lists - this is ugly, expensive, and by far the most shameful of this code + } elsif ($lines[$i] =~ m/^(\t{1,}|\s\s{1,})(\*\s|\~\s|\-\s|\+\s|.{1,3}\.\s)(.*)/) { + # this is hackish - I would prefer to get # of matches from above + my $depth = length($1) / (substr($1, 0, 1) eq ' ' ? 2 : 1); + if (%block) { + if ($block{"type"} != TYPE_LIST) { + push @elements, {%block}; + %block = (type => TYPE_LIST, depth => 0, children => []); + } + } else { + %block = (type => TYPE_LIST, depth => 0, children => []); + } + my %this_item = (type => TYPE_LIST, text => parseText($3), depth => $depth, parent => \%block, children => []); + my $child_count = @{$block{'children'}}; + if ($child_count == 0) { + push @{$block{'children'}}, {%this_item}; + } else { + my $root = \%block; + my $root_children = \@{${$root}{'children'}}; + my $diff = $depth-${$root}{'depth'}; + # travel down the list until we get our proper context. + while ($diff > 0) { + $root_children = \@{${$root}{'children'}}; + if (@{${$root}{'children'}} <= 0) { + push @{${$root}{'children'}}, {%this_item}; + $diff = 0; + } else { + # diff 1 = we have proper parent, 0 = we're one step too deep + $root = $root_children->[-1]; + $diff = $depth-${$root}{'depth'}; + if ($diff == 1) { + push @{${$root}{'children'}}, {%this_item}; + $diff = 0; + } elsif ($diff == 0) { + push @{${${$root}{'parent'}}{'children'}}, {%this_item}; + } + } + } + } + # preformatted (default) + } else { + if (!%block) { + if ($2 eq '.' && $3 =~ m/^(.*\)(\s|))(.*)/) { + %block = (type => TYPE_PRE, text => $3, opts => parseOptions('.'.$1)); + } else { + %block = (type => TYPE_PRE, text => $2.$3); + } + } else { + if ($block{"type"} != TYPE_PRE) { + push @elements, {%block}; %block=(); + if ($2 eq '.' && $3 =~ m/^(.*\)(\s|))(.*)/) { + %block = (type => TYPE_PRE, text => $3, opts => parseOptions('.'.$1)); + } else { + %block = (type => TYPE_PRE, text => $2.$3); + } + } else { + $block{'text'} .= "\n".$2.$3; + } + } + } + next; + } + # 2. check for big headers, e.g., + # ,,,, + # header + # ```` + # conditions: first and third lines must have at least 4 repeating chars, and the second line must not match header conditions. + if ($i+1 < $#lines) { + if ($lines[$i] =~ m/(\S\S)\1{2,}/) { + my $size = $+[0]; + # only check closing header if contents appear to not be a header + if ($lines[$i+1] !~ m/(\S\S)\1{2,}/g) { + # check closing line for header appearance + if ($lines[$i+2] =~ m/(\S\S)\1{2,}/g) { + if (%block) { push @elements, {%block}; %block=() } + if ($lines[$i+1] =~ m/^(.*?)(\..*\))/) { + push @elements, { + type => TYPE_HEADER, + size => $size, + text => parseText($1), + opts => parseOptions($2) + }; + } else { + push @elements, { + type => TYPE_HEADER, + size => $size, + text => parseText($lines[$i+1]) + }; + } + $i += 2; + next; + } + } + } + } + # 3. check for small headers + if ($lines[$i] =~ m/(\S)\1{2,}/) { + my $size = $+[0]; + my $match = substr($lines[$i], $-[0], $+[0]-$-[0]); + my $post = substr($lines[$i], $+[0]); + # two conditions: + # match repeated $match if something else came between + # e.g., ==== header ==== + # otherwise match if there is some text following + # e.g., ==== header + if ($post =~ m/(\t*|\s*|)(.*)$match$/g) { + if (%block) { push @elements, {%block}; %block=() } + if ($2 =~ m/^(.*?)(\..*\))/) { + push @elements, { + type => TYPE_HEADER, + size => $size, + text => parseText($1), + opts => parseOptions($2) + }; + } else { + push @elements, { + type => TYPE_HEADER, + size => $size, + text => parseText($2) + }; + } + next; + } elsif ($post =~ m/^(\t*|\s*|)(.*[^(\n|\r|\s|\t)])/g) { + if (%block) { push @elements, {%block}; %block=() } + if ($post =~ m/^(.*?)(\..*\))/) { + push @elements, { + type => TYPE_HEADER, + size => $size, + text => parseText($1), + opts => parseOptions($2) + }; + } else { + push @elements, { + type => TYPE_HEADER, + size => $size, + text => parseText($post) + }; + } + next; + } + } + # 4. check for spacers + if ($lines[$i] =~ m/^(\S)\1{2,}/) { + if (%block) { push @elements, {%block}; %block=() } + push @elements, { + type => TYPE_SPACER, + size => $+[0]-$-[0] + }; + next; + } + # discover blank lines - these usually signify end of some type of block + if ($lines[$i] =~ m/^\s*$/) { + if (%block) { push @elements, {%block}; %block=() } + push @elements, { + type => TYPE_BREAK + }; + next; + } + # check for blockquotes + if ($lines[$i] =~ m/^\>(.*)$/) { + if (!%block) { + if ($1 =~ m/^(\..*\)(\s|))(.*)/) { + %block = (type => TYPE_BLOCKQUOTE, text => $2, opts => parseOptions($1)); + } else { + %block = (type => TYPE_BLOCKQUOTE, text => $1); + } + } else { + if ($block{'type'} != TYPE_BLOCKQUOTE) { + push @elements, {%block}; + if ($1 =~ m/^(\..*\)(\s|))(.*)/) { + %block = (type => TYPE_BLOCKQUOTE, text => $2, opts => parseOptions($1)); + } else { + %block = (type => TYPE_BLOCKQUOTE, text => $1); + } + } else { + $block{'text'} .= "\n".$1; + } + } + next; + } + # finally, create a paragraph or append to it. + if (!%block) { + if ($lines[$i] =~ m/^(\..*\)(\s|))(.*)/) { + %block = (type => TYPE_PARAGRAPH, text => parseText($2), opts => parseOptions($1)); + } else { + %block = (type => TYPE_PARAGRAPH, text => parseText($lines[$i])); + } + } else { + $block{'text'} .= "\n".parseText($lines[$i]); + } +} +# push final block if it exists +if (%block) { push @elements, {%block}; %block=() } +# merge file settings with command-line settings +@settings{ keys %cmd_settings } = values %cmd_settings; +# get our various header sizes and organize an array with unique values from smallest to largest. +my @headers; +foreach (@elements) { + my $element = $_; + if ($element->{type} == TYPE_HEADER) { + if (@headers) { + my $h_i = 0; + my $last_size = $headers[0]; + for (my $h_i = 0; $h_i < scalar @headers; $h_i++) { + if ($element->{size} == $headers[$h_i]) { + $h_i = scalar @headers; + } elsif ($element->{size} < $headers[$h_i]) { + splice @headers, $h_i, 0, $element->{size}; + $h_i = scalar @headers; + } elsif ($element->{size} > $headers[$h_i]) { + if ($h_i+1 >= scalar @headers) { + splice @headers, $h_i+1, 0, $element->{size}; + $h_i = scalar @headers; + } + } + } + } else { + $headers[0] = $element->{size}; + } + } +} +# this is really dumb, but convert our array to a hash +my %header_map; +for (my $h_i = 0; $h_i < scalar @headers; $h_i++) { + if ($settings{'header.reverse'}) { + $header_map{$headers[$h_i]} = $h_i+1+($settings{'header.depth'} ? $settings{'header.depth'} : 0); + } else { + $header_map{$headers[$h_i]} = scalar ($settings{'header.depth'} ? $settings{'header.depth'} : 0) + @headers - $h_i; + } +} + +# print 'em out +if ($settings{'toc'}) { + foreach (@elements) { + if ($_->{type} == TYPE_HEADER) { + + } + } +} else { + my $previous_type = 0; + my $indent = ("\t" x ($settings{"indent_level"} ? $settings{"indent_level"} : 0)); + foreach (@elements) { + if ($_->{type} == TYPE_HEADER) { + my $hsize = $header_map{$_->{size}}; + my $htext = $_->{text}; + my $hid = $_->{text}; + $hid =~ s/ /_/g; + print("{opts} ? $_->{opts} : '').($settings{'header.ids'} ? " id=\"".$hid."\"" : '').">$_->{text}\n"); + } elsif ($_->{type} == TYPE_BREAK) { + if ($previous_type == TYPE_BREAK) { + print("
\n"); + } + } elsif ($_->{type} == TYPE_PARAGRAPH) { + print("{opts} ? $_->{opts} : '').">$_->{text}

\n"); + } elsif ($_->{type} == TYPE_PRE) { + print("{opts} ? $_->{opts} : '').">$_->{text}\n"); + } elsif ($_->{type} == TYPE_CODE) { + print("
{opts} ? $_->{opts} : '').">$_->{text}
\n"); + } elsif ($_->{type} == TYPE_BLOCKQUOTE) { + print("{opts} ? $_->{opts} : '').">".($settings{'blockquote.parse'} ? parseText($_->{text}) : $_->{text})."\n"); + } elsif ($_->{type} == TYPE_SPACER) { + print("
\n"); + } elsif ($_->{type} == TYPE_LIST) { + printList($_); + } + $previous_type = $_->{type}; + } +} +if (!$settings{"version.none"}) { + if ($settings{"version.hide"}) { + print "\n"; + } else { + print "$file_name generated by kettext 0.1\n"; + } +} + +sub printList { + my $list = $_[0]; + my $child_count = @{$list->{'children'}}; + #my $child = $children->[$child_i]; + if ($list->{'text'}) { + print "
  • $list->{'text'}"; + } + if ($child_count > 0) { + print "
      \n"; + my $children = \@{$list->{'children'}}; + my $child_i = 0; + for (my $child = $children->[$child_i]; $child_i < $child_count; $child = $children->[++$child_i]) { + printList($child); + } + print "
    \n"; + } + if ($list->{'text'}) { + print "
  • \n"; + } +} + +sub parseText { + my $text = $_[0]; + my @text_patterns = ('\*\*','\*\*', '\/\/','\/\/', '\[\[','\]\]', '\(\(','\)\)', '``', '``'); + my @text_replace = ('','', '','', '
    ','', '','', '',''); + my $i = 0; + my $new_text = $text; + for (my $p = 0; $p <= $#text_patterns; $p+=2) { + my $open = $text_patterns[$p]; + my $close = $text_patterns[$p+1]; + while ($new_text =~ m/($open)([^$close]*)($close)(\.\S*\(.*?\)|)/g) { + #while ($new_text =~ m/($open)([^$close]*)($close)(\.\S*\(.*\)|)/g) { + my $converted_text; + if ($4) { + my $ts = substr($text_replace[$i], 0, -1); + my $te = substr($text_replace[$i], -1); + $converted_text = $ts.parseOptions($4).$te.$2.$text_replace[$i+1]; + } else { + $converted_text = $text_replace[$i].$2.$text_replace[$i+1]; + } + $new_text =~ s/\Q$1$2$3$4\E/$converted_text/g; + } + $i +=2; + } + return $new_text; +} + +sub parseOptions { + my $text = $_[0]; + my $opts; + while ($text =~ m/(\.)([a-zA-Z]*[^\(])(\()([^\)]*)/g) { + $opts.=" $2=\"$4\""; + } + return $opts; +} diff --git a/test/all.ktx b/test/all.ktx new file mode 100644 index 0000000..86809d4 --- /dev/null +++ b/test/all.ktx @@ -0,0 +1,124 @@ +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +Headers +```````````````````````````````````````````````````````````````` + #,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, + #Header 1 + #```````````````````````````````` +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +Header 1 +```````````````````````````````` +---- + #,,,,,,,,,,,,,,,,,,,,,,,, + #Header 2 + #```````````````````````` +,,,,,,,,,,,,,,,,,,,,,,,, +Header 2 +```````````````````````` +---- + #======== Header type 2 ======== +======== Header type 2 ======== +---- + #===== Header type 2 ===== +===== Header type 2 ===== +---- + #===== Header type 3 +===== Header type 3 + +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +Paragraphs / Blocks +```````````````````````````````````````````````````````````````` + #This is just a multispace + #paragraph + +This is just a multispace +paragraph + +---- + + # This is just a multispace + # preformatted paragraph that can + # + # jump! + + This is just a multispace + preformated paragraph that can + + jump! + +---- + + # #This is just a multispace + # #code block that can + # # + # #also jump! + + #This is just a multispace + #code block that can + # + #also jump! + +---- + + #> This is a blockquote + #> that can, of course, + #> + #> jump! + +> This is a blockquote +> that can, of course, +> +> jump! + +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +Text +```````````````````````````````````````````````````````````````` + #**bold** + # + #//italics// + # + #__underline__ + # + #--strikethrough-- + # + #((small)) + # + #[[anchor]].href(all.html) + +**bold** + +//italics// + +__underline__ + +--strikethrough-- + +((small)) + +[[anchor]].href(all.html) + +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +Lists +```````````````````````````````````````````````````````````````` + # * This is a list + # * Item 1 + # * Item 2 + # * Item 3 + # * Item 4 + # * Another list! + + * This is a list + * Item 1 + * Item 2 + * Item 3 + * Item 4 + * Another list! + +---- + + # 1. This is a numbered list + # a. This also works. + # 2. Yep! + + 1. This is a numbered list + a. This also works. + 2. Yep! diff --git a/test/code.ktx b/test/code.ktx new file mode 100644 index 0000000..f4b8fe0 --- /dev/null +++ b/test/code.ktx @@ -0,0 +1,3 @@ + #.class(food) + #yep + # thisi s a diff --git a/test/example.ktx b/test/example.ktx new file mode 100644 index 0000000..b78c9ca --- /dev/null +++ b/test/example.ktx @@ -0,0 +1,45 @@ +.set(headers 3) + +kettext is designed to be an HTML-friendly markup language that looks nice in plain terminals. Contrary to other markup syntax, kettext attempts to provide very few strict formatting rules, opting instead for intelligent detection of intent. + +For example, headers do not use specific formatting characters, but rather the repitition of characters in a particular pattern. These patterns may be: +,,,, +header +```` +.,.,.,., +Rabble! +.,.,.,., +==== header +---- header +~~~~ header +~~~~ header ~~~~ + +If a character type repeats > 8 times in a line, it triggers a "maybe title" mode +If another character type repeats > 8 times in the next line, it switches to regular +If the third line repeats > 8 times, it text between first and now are a title + +Headers are presumed to be at a depth of 0, but can be overrided by providing a depth override: + .set(headers 3) + +Header precidence is for larger lines to be considered as lower (i.e., "`````````" = h1; "````" = h2) + +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +My Header .name(my_header) +```````````````````````````````` +Some text! +,,,,,,,,,,,,,,,, +Sub Header .name(sub_header) +```````````````` + += Title .name(title) = +== Title 2 == +=== Title 3 === + +This file is an example of kettek text formatting! + +* list 1 + * list 2 + * list 3 +- list 1 + - list 2 + - list 3 diff --git a/test/header.ktx b/test/header.ktx new file mode 100644 index 0000000..a4214cd --- /dev/null +++ b/test/header.ktx @@ -0,0 +1,9 @@ +,,,,,,,,,,,,,,,, +Header 1 .name(header_1).class(yo_1) +```````````````` +:) + +,,,,,,,, +Header 2 +```````` +L:p diff --git a/test/header_test.ktx b/test/header_test.ktx new file mode 100644 index 0000000..c9f691e --- /dev/null +++ b/test/header_test.ktx @@ -0,0 +1,23 @@ +,,,,,,,,,,,,,,,,,,,,,,,, +Header 1 +```````````````````````` +This is a header 1 paragraph +,,,,,,,,,,,,,,,, hue +Header 2 +```````````````` +This is a header 2 paragraph +==== Header 3 ==== +This is a header 3 paragraph :S +====== Header 4 ---- +This is a header 4 paragraph + indentation! + again + + ok + +ok +chump + +====Header 5 .name(yo) +This is a header 5 paragraph +This is the second line. diff --git a/test/list.ktx b/test/list.ktx new file mode 100644 index 0000000..b6eb4d0 --- /dev/null +++ b/test/list.ktx @@ -0,0 +1,15 @@ +,,,,,,,,,,,,,,,,,,,,,,,, +Lists +```````````````````````` + * item 1 + * sub-item 1 + * sub-sub-item 1 + * sub-item 2 + * sub-sub-item 2 + * sub-sub-item 2.3 + * sub-sub-sub-item 2 + * sub-item 3 + * ok + * hue + * item 2 + * item 3 diff --git a/test/lists.ktx b/test/lists.ktx new file mode 100644 index 0000000..36a5346 --- /dev/null +++ b/test/lists.ktx @@ -0,0 +1,31 @@ +,,,,,,,,,,,,,,,,,,,,,,,, +Lists +```````````````````````` + * item 1 + * sub-item 1 + * item 2 + * item 3 + + - item 1 + - sub-item 1 + - item 2 + - item 3 + + + item 1 + + sub-item 1 + + item 2 + + item 3 + + 1. item 1 + 1. sub-item 1 + 2. item 2 + 3. item 3 + + 10. item 1 + 20. item 2 + 30. item 3 + + a. item 1 + a. sub-item 1 + b. item 2 + c. item 3 diff --git a/test/paragraph.ktx b/test/paragraph.ktx new file mode 100644 index 0000000..9601f07 --- /dev/null +++ b/test/paragraph.ktx @@ -0,0 +1,57 @@ +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +Basic Paragraph Formatting +```````````````````````````````` +,,,,,,,,,,,,,,,, +Regular Paragraphs +```````````````` +This is a regular paragraph, it may continue on one line +or it may continue on the next. + +An empty line will create a new paragraph. +,,,,,,,,,,,,,,,, +Block quotes +```````````````` +> This is a block quote. It follows the same rules +> as paragraphs, but requires a ">" on each line. +> +> An empty line started with ">" in a blockquote will continue a blockquote. + +> Otherwise, an empty line will break. +,,,,,,,,,,,,,,,, +Preformatted Text +```````````````` + Preformatted text is marked by a tab, 2 spaces, or 4 spaces. + It follows the same rules as block quotes, but using tabs/spaces. + + This includes empty lines if they are to be of the same preformatted block. + + Empty lines will break. +,,,,,,,,,,,,,,,, +Code +```````````````` + # Code is started by a tab, 2 spaces, or 4 spaces followed by a pound. + # It follows the same rules as preformatted text, but adding a pound. + # + # This includes empty lines. + + # Empty lines will break. +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +Paragraph Formatters +```````````````````````````````` +Paragraphs may apply formatters by adding formatters to an otherwise empty line in the style's format. Examples: + +.class(alt_paragraph) +This is a +paragraph + +>.class(alt_block) +> This is a blockquote +> :) + + .class(alt_pre) + This is a preformatted + paragraph. + + #.class(alt_code) + # This is a code + # paragraph. diff --git a/test/proclib.ktx b/test/proclib.ktx new file mode 100644 index 0000000..3b783fd --- /dev/null +++ b/test/proclib.ktx @@ -0,0 +1,633 @@ +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +Preface +```````````````````````` +What is proclib? A library and syntax language for structure-centric world/map generation. But what is "structure-centric", you ask? Easy, I'll explain! + +Structures can be thought of as complex collections of entities/cells. From this, structures can be made up of other structures to increase the variation and complexity needed for a structure. Examples of structures are: castles, moats, ravines, towns, rooms, and much more. + +Towards the end of (easily?) creating complicated maps, I've created this structure generation syntax and library/codebase written in C. + +Also, you can make weird faces in it: + + ...............1...........1............ + .............11111......1111111......... + ............1111011....111101111........ + ...........111000001..11100000111....... + ............1111011....111101111........ + .............11111......1111111......... + ...............1...........1............ + ........................................ + ........................................ + ......0................................. + ......000000000000000..............0.... + .......0...0.0...0.00000000000000000.... + ........................00....0..00..... + +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +Syntax +```````````````````````` +,,,,,,,,,,,,,,,, +Basic Syntax +```````````````` +As it stands, structures are written in plain text files with very simple formatting rules. To begin with, a structures file can contain an (unlimited) amount of structures within it. Each structure can have various settings applied that alters the generation behaviors. The basic variable settings are: + + * **flags** -- defines the generation behavior using bitflags. Multiple flags can be set by piping them together (ex. "flags CIRCLE|BORDER|ORIGIN") + * Shape Generation + * //CIRCLE// - Bresenham-like ellipse generation + * //RECT// - basic "box" generation + * Shape Modification + * //BORDER// - creates an interior border using the current shape + * //IGNORE_EMPTY// - ignores cells that are empty (i.e., have no id_s written to them) + * Structure Placement + * //ORIGIN// - places the structure from its center + * //OVERLAP// - overlaps the structure on top of other potential structures + * **size_x, size_y** -- defines the size of the structure. Values may be: + * single numbers (e.g., "4") + * percentages (e.g., "50%" of parent's size) + * ranges of either (e.g., "25%~50%"). + * If omitted, defaults to 0, 0 + * **x, y** -- defines the position of the structure. Values may be: + * single numbers (e.g., "-4", "4") + * percentages (e.g., "-50%", "50%") + * ranges of either (e.g., "-50%~50%"). + * If omitted, defaults to 0, 0 + * **id_1** -- first id of the structure. Values may be: + * single numbers (e.g., "2") + * ranges (e.g., "1~4") + * comma-delimited sets of either (e.g., "2, 1~4") + * **id_2** -- second id of the structure. Follows same rules as id_1 + +Before delving into more complicated aspects of structure definitions, let us use some of the above information to create a simple structure. + +,,,,,,,,,,,, +A Simple Circle +```````````` +A rudimentary example that creates a variable-sized tower in the middle of the screen would be: + + tower { + flags CIRCLE + size_x 12~16 + size_y 9~14 + id_1 0 + } + +This would generate structures similar to the following: + + ........................................ + ....................0................... + .................0000000................ + ................000000000............... + ...............00000000000.............. + ...............00000000000.............. + ..............0000000000000............. + ...............00000000000.............. + ...............00000000000.............. + ................000000000............... + .................0000000................ + ....................0................... + ........................................ + +,,,,,,,,,,,,,,,, +Complex Syntax: Relations +```````````````` +Every structure can have 3 additional sets of information. The first I will cover is **relations**. A relation is, as the name implies, a relationship to another structure. In general, relations are used to create sub-structures within a structure. + +**Relations** are contained with a relations block, and each relation is defined in a similar method as a regular structure. Acceptable settings are: + + * **flags** -- same as structure flags, but override and/or stack on top of the given structure's flags + * **x, y** -- override position settings + * **count** -- defines how many times to generate this relation. Values may be: + * single numbers (e.g., "2") + * ranges (e.g., "2~6"). + * If omitted, defaults to 1. + +Using this new information, let us expand upon the earlier tower. + +,,,,,,,,,,,, +A Simple Tower +```````````` +An ellipse by itself is rather boring, but we can spice things up by using relations to create walls: + tower { + flags CIRCLE + size_x 12~16 + size_y 9~14 + id_1 0 + relations { + tower_walls { + flags CIRCLE|OVERLAP + } + } + } + tower_walls { + flags BORDER + size_x 100% + size_y 100% + id_1 1 + } + +This would generate a structure similar to the following: + ........................................ + ...................1.................... + ................1111111................. + ..............11100000111............... + ..............10000000001............... + .............1100000000011.............. + ..............10000000001............... + ..............11100000111............... + ................1111111................. + ...................1.................... + ........................................ + +,,,,,,,,,,,,,,,, +Complex Syntax: Replace +```````````````` +With the concept of relations out of the way, we can move into the **replace** functionality. + +**Replace** rules are contained in a replace block and define what type of **id_1** and **id_2** tiles may be replaced. The possible values in a replace block are: + + * **id_1** -- list of primary IDs that may be replaced. Values may be: + * single positive numbers (e.g., "4") + * positive ranges (e.g., "1~4") + * comma-delimited sets of either (e.g., "1, 3~8, 12) + * **id_2** -- list of secondary IDs that may be replaced. Values may be the same as id_1. + +For this example, we're going to use another structure to remove a section of walls from the tower. + +,,,,,,,,,,,, +Holy Tower +```````````` + tower { + flags CIRCLE + size_x 12~16 + size_y 9~14 + id_1 0 + relations { + tower_walls { + flags CIRCLE|BORDER|OVERLAP + } + hole { + x 50% + y 50% + } + } + } + tower_walls { + flags BORDER + size_x 100% + size_y 100% + id_1 1 + } + hole { + flags RECT|IGNORE_EMPTY + size_x 100% + id_1 0 + replace { + id_1 1 + } + } + +What we've done here is create a new "hole" structure that replaces any overlapping cell with an id_1 of "1" with "0". We've added this structure as a relation to the tower so that it is applied appropriately. The IGNORE_EMPTY flag is only used to prevent the replacement of empty (unset) tiles. + +The resulting replacement would generate something similar to: + ........................................ + ...................1.................... + ................1111111................. + ..............11100000111............... + ..............10000000001............... + .............1100000000000.............. + ..............10000000000............... + ..............11100000000............... + ................1111000................. + ...................1.................... + ........................................ + +,,,,,,,,,,,,,,,, +Complex Syntax: Paths +```````````````` +The (currently!) final important structure generating concept is that of **paths**. The first key concept is to realize that paths are generated in a separate pass from initial structures. During structure generation, structures are built and then recorded as "live structures". After this, these live structures are checked for any pathing configuration, and if found, a pathing pass is made. The pathing pass itself generates new live structures for every path "step" made (kept separately from the previous!) and handles the building as per normal operations. + +A **path** is a configuration within a structure that defines some form of pathing behavior. This includes from/to destination structures, position offsets, structure to use for pathing, pathing algorithm, and others. Acceptable settings for a path are: + + * **flags** -- these define the behaviors of the pathing + * Algorithms/Movement + * //DUMB// -- doggedly move towards "to" by incrementing or decrementing x and y position. Is stopped by cells that cannot be replaced and are not empty. + * //A*// -- uses A* to intelligently move towards position (NOT IMPLEMENTED (YET!)) + * //WALK// -- only move one cell in one direction at a time (e.g., x+1 OR y+1, not both) + * //WANDER// -- some odd chance to randomly move x or y in a direction. Requires an Algorithm. + * Looping + * //ALL// -- attempt to path find to all targets that match the to pathing syntax + * Etc. + * //FORCE// -- if pathing movement fails too many times(>32), force movement anyway + * //UNIQUE// -- only look for from/to targets that have not been pathed to/from by this structure + * **to** -- pathing syntax for the structure to path to - REQUIRED + * **to_flags** -- flags that define a specific "to" behavior + * //ORIGIN// -- you guessed it, to_x/to_y values are relative to the center of the target + * **to_x, to_y** -- position to path to. Values may be: + * single numbers (e.g., "1", "-1") + * percentages (e.g., "25%") + * ranges (e.g., "-25%~25%", "-5~5") + * sets of any (e.g., "1, 25%, -5~5") + * **from** -- pathing syntax for the structure to path from. If omitted, defaults to the structure making this path. + * **from_flags** -- same as to_flags + * **from_x, from_y** -- same as to_x, to_y + * **x, y** -- positional data that is applied to each pathing step. Values may be: + * single numbers (e.g., "-1") + * ranges (e.g., "-1~1") + * sets of either (e.g., "-1, -1~1") + +,,,,,,,,,,,, +Pathing Syntax +```````````` +Pathing syntax, used for **to** and **from** in pathing, refers to live structures and uses a straight-forward syntax contained in a single string. An example pathing syntax string could be: ":tower:hole" The following are the single-character "commands" used to acquire a live structure. + + * **:** -- if the first character of the string, get the global "root" live structure + * **:** -- otherwise it is used a position delimiter to specify parent->child + * **^** -- get parent of this context's live structure + +These can be combined to acquire live structures in complex structures. Examples: + + * "tower" -- look for a structure named "tower" in the current context. + * ":tower" -- look for a structure named "tower" in the root context. + * "^tower" -- look for a structure named "tower" in the parent of the current context. + * "^^towers:tower:room" -- look for a structure named "room" in "tower" in "towers" in the parent of the parent of the current context. + +Context is assumed to be the live structure containing the path definitions. +Let us use this new-found knowledge to create a road between the towers of two rival wizards. +,,,,,,,,,,,, +The Two Towers +```````````` +This example expands on the preceding example by creating a wall-removing path between two towers. + tower { + flags CIRCLE + size_x 8~12 + size_y 7~10 + id_1 0 + relations { + tower_walls { + flags CIRCLE|OVERLAP + } + } + } + tower_walls { + flags BORDER + size_x 100% + size_y 100% + id_1 1 + } + dirt_path { + flags RECT + size_x 1 + size_y 1 + id_1 0 + replace { + id_1 1 + } + } + towers { + size_x 100% + size_y 100% + relations { + tower { + count 2 + x 10~75% + y 10~75% + } + } + paths { + dirt_path { + flags DUMB|WALK + to tower + to_flags ORIGIN + from tower + from_flags ORIGIN + } + } + } + +This would create a scene similar to: + ...............1........................ + ............1111111..................... + ...........110000011.................... + ..........11000000011................... + ...........110000011.......1............ + ............1111100.....1111111......... + ...............1..00...110000011........ + ...................00..100000001........ + ....................0011000000011....... + .....................00000000001........ + .......................110000011........ + ........................1111111......... + ...........................1............ + +This should give a fairly concise overview of proclib, although there are likely to be massive enhancements and changes in the future. :) +,,,,,,,,,,,,,,,, +Other Examples +```````````````` +,,,,,,,,,,,, +Little House by the Lake +```````````` + ................................................................ + .........8.......8.........8.8.........88......8.8.............. + ......11111111111.........8....8........................8....... + ......10000000001.........8....8................................ + .....8100000000018.8........................8....8.............. + ......11111111111.............8.8...........8...............8... + .......................8........................................ + ......8.......8...........................8.....8...........8..8 + ............................................8................... + ..8........................8......8.........................8... + ...8..8....8.......8....8........8.............................. + ........................................8..............8........ + .......8.....................8....8......................8...... + ..........8..8.........88........................8...8...8..8... + ......8...............8..8.......8.................8.....0....8. + ......88...............8.................8..........000000000000 + ...8.............8...............................000000000000000 + ..8....8...............88.......................0000000000000000 + ............................8.................000000000000000000 + ....8..................8......8.........8....0000000000000000000 + ........8..............8....................00000000000000000000 + ...................................8.......000000000000000000000 + .....8..........8...8.........8............000000000000000000000 + +-------- + + tree { + flags RECT + size_x 1 + id_1 8 + } + lake { + flags CIRCLE|OVERLAP + size_x 50~75% + id_1 0 + } + house { + flags RECT + size_x 9~14 + size_y 4~7 + id_1 0 + relations { + house_walls { + flags RECT + } + } + } + house_walls { + flags BORDER|OVERLAP + size_x 100% + size_y 100% + id_1 1 + } + start { + size_x 64 + size_y 32 + relations { + lake { + count 4~6 + x 50~80% + y 70~80% + } + tree { + count 64~128 + x 0~100% + y 0~100% + } + house { + flags OVERLAP + count 1 + x 10~50% + y 10~50% + } + } + } + +,,,,,,,,,,,, +Lumpy Castle +```````````` +The structure definition for this one is exceptionally bad and could be refactored. + + ................................................................. + ............................................................9.... + ...9.......1.........................9........1.................. + ........1111111............................1111111............... + .......110000011..........................1100000119............. + .......100000001..........................100000001.............. + .......100000001.....................9....100000001......9....... + ......1100000001111111111111111111111111111000000011............. + .......100000000000000000000000000000000000000000001............. + .......100000000000000000000000000000000000000000001............. + .......110000001111111111111111111111111111100000011....9........ + ........11000011...........9...............11000011.............. + .........100001.............................100001............... + .........100001..............1......9.......100001............... + .........100001...........1111111...........100001............... + .........100001...9......110000011..........100001............... + .........100001..........100000001..........100001............... + .........100001........9.100000001..........100001..............9 + .........100001.........11000000011.........100001............... + .........100001..........100000001..........100001............... + .........100001..........100000001..........100001............... + .9.......100001..........110000011..........100001............... + .........100001...........1111111...........100001............... + .........100001.....9........1..............100001............... + ........1100001............................1100001............... + .......110000011..........................110000011.............. + .......100000001..........................100000001.............. + .......100000001..........................100000001....8......... + ......1100000001111111111111111111111111111000000011.88888....... + .......10000000000000000000000000000000000000000001..88888....... + .9.....10000000000000000000000000000000000000000001.8888888...... + .......11000001111111111111111111111111111110000011..88888....... + ........1111111............................1111111...88888....... + ...........1.................................81........8......... + ...........................................88888................. + .............................9.............88888.............9... + ..........................................8888888................ + ...........................................88888................. + ...........................................88888................. + .............................................8................... + .................9........9.......9.............................. + +-------- + + lake { + flags CIRCLE|ORIGIN + size_x 6~9 + id_1 8 + } + tree { + flags RECT|ORIGIN + size_x 1 + id_1 9 + replace { + id_1 9 + } + } + tower_1 { + flags CIRCLE|ORIGIN + size_x 20% + id_1 0 + relations { + tower_walls { + flags OVERLAP + } + } + } + tower_2 { + flags CIRCLE|ORIGIN + size_x 20% + id_1 0 + relations { + tower_walls { + flags OVERLAP + } + } + } + tower_3 { + flags CIRCLE|ORIGIN + size_x 20% + id_1 0 + relations { + tower_walls { + flags OVERLAP + } + } + } + tower_4 { + flags CIRCLE|ORIGIN + size_x 20% + id_1 0 + relations { + tower_walls { + flags OVERLAP + } + } + } + tower_5 { + flags CIRCLE|ORIGIN + size_x 20% + id_1 0 + relations { + tower_walls { + flags OVERLAP + } + } + } + tower_walls { + flags CIRCLE|BORDER + size_x 100% + size_y 100% + id_1 1 + } + long_walls { + size_x 10% + size_y 10% + flags RECT|ORIGIN + id_1 0 + replace { + id_1 1 + } + relations { + long_walls_walls { + } + } + } + long_walls_walls { + flags RECT|BORDER|ORIGIN|OVERLAP + size_x 100% + size_y 100% + id_1 1 + replace { + id_1 0 + } + } + castle { + size_x 90% + size_y 90% + relations { + tower_1 { + x 20% + y 20% + } + tower_2 { + x 20% + y 80% + } + tower_3 { + x 80% + y 20% + } + tower_4 { + x 80% + y 80% + } + tower_5 { + flags ORIGIN + x 50% + y 50% + } + } + paths { + long_walls { + flags DUMB|WALK|FORCE + from tower_1 + from_flags ORIGIN + to tower_2 + to_flags ORIGIN + to_x -25% + } + long_walls { + flags DUMB|WALK|FORCE + from_flags ORIGIN + from_x 0% + from_y 0% + to_flags ORIGIN + to_x 0% + to_y 0% + from tower_1 + to tower_3 + } + long_walls { + flags DUMB|WALK|FORCE + from_flags ORIGIN + from_x 0% + from_y 0% + to_flags ORIGIN + to_x -25% + to_y 0% + from tower_3 + to tower_4 + } + long_walls { + flags DUMB|WALK|FORCE + from_flags ORIGIN + from_x 0% + from_y 0% + to_flags ORIGIN + to_x 0% + to_y 0% + from tower_4 + to tower_2 + } + } + } + start { + size_x 64~80 + size_y 32~48 + relations { + castle { + } + tree { + count 16~32 + x 0~100% + y 0~100% + } + lake { + count 1~2 + x 70~100% + y 70~100% + } + } + } +.imply(header.ids,header.depth=2,version.hide) diff --git a/test/spacer.ktx b/test/spacer.ktx new file mode 100644 index 0000000..8d3924d --- /dev/null +++ b/test/spacer.ktx @@ -0,0 +1,7 @@ +Spacer +---- + +Yep + ======== + +woo diff --git a/test/test.ktx b/test/test.ktx new file mode 100644 index 0000000..94eed7c --- /dev/null +++ b/test/test.ktx @@ -0,0 +1,132 @@ +.imply(header.ids) +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +kettext live example! .name(kettek_live) .class(css_class) +```````````````````````````````` +This file show some fun stuff with kettext +,,,,,,,,,,,,,,,,,,,,,,,, +Formatters +```````````````````````` +kettext makes heavy use of "formatters" - commands that modify the given text-to-be-formatted. These formatters may be appended or prepended, depending on the target text. The full list is: + + * .class(my_class) -- sets the class of the element + * .id(my_id) -- sets the id + * .name(my_name) -- sets the name + * .a(wew) -- creates an anchor around the given block + +,,,,,,,,,,,,,,,,,,,,,,,, +Emphasis and Text Formatting +```````````````````````` +Emphasis and formatting is specified via various double characters on either side of the text: + + * **bold** + * //italics// + * __underline__ + * --strike-- + * !!important!! + * ((inline)) + * [[anchor]] + +Formatters may be applied to any of the above by appending to the text, e.g., + + * **bold**.class(my_Text) + * [[anchor]].href(http://kettek.exoss.net/) + +,,,,,,,,,,,,,,,,,,,,,,,, +Anchors / Links / References +```````````````````````` +Links can be attached via the ".href(...)" formatter to an anchor: + + * See: [[John Doe's Local Family]].href(#john_doe) + * See: [[John Doe's Family]].href(john_doe) + * See: [[John Doe's Foreign Family]].href(www.someplace.jp/john_doe) + * See: [[John Doe's Hyper Family]].href(http://someotherplace.it/john_doe) + +Links may also have formatters appended: + + * See: [[John Doe's Secure Family]].href(https://pluto.net/john_doe).class(alternative) + +,,,,,,,,,,,,,,,,,,,,,,,, +Paragraphs +```````````````````````` +Paragraphs are simply lines of text such as this that may +or may not have a link break. + +Paragraphs are separated by blank lines. :) + +If a paragraph starts with any of the formatters, whether alone or prepended to the first-line, +the paragraph will inherit accordingly. Ex. ".name(my_paragraph) .class(css_class)" + +.name(my_paragraph) .class(my_class) +This is a paragraph with the name "my_paragraph" of the class "my_class"! + +,,,,,,,,,,,,,,,,,,,,,,,, +Preformatted Text and Code +```````````````````````` +Pre-formatted text is a simple matter of using indentation. + + This is a preformatted block + of text + +Formatters may also be used: + + .name(my_pre) .class(my_pre) + This is a preformatted block + named "my_pre" using the class "my_class" + + You can also use empty lines providing + you keep the indentation. :) + +Code is specified by adding indent+'#': + + #.name(my_code) .class(my_code) + #This is a code block named "my_code" + #with class "my_code" + # + #Yay! :) + +You can place multiple pre or code blocks after one another. + + hi there, this is pre + + #and this is code. :) + +,,,,,,,,,,,,,,,,,,,,,,,, +Lists +```````````````````````` +Lists are managed either by some alpha-numerical combined with a period (e.g., "a."), or by a repeating non-alphanumerical character. + +a. my list! + b. my list! + c. my list! +1. my list + 2. my list + 3. my list! +* my list + * my list +- my list + - my list + +,,,,,,,,,,,,,,,,,,,,,,,, +Definitions +```````````````````````` +Definition lists are similar, but use a ":" for the punctuation and must have indentation + + Word: This is a word + + Word2: + This is another word + It can span multiple lines + + Word3: + Yep. + + Word4: + Alt4: + Yep. + +Alternatively, you can create a definition in the following manner: + +Word +Alt Word + A word is a word indeed! + It can also span multiple lines. :) diff --git a/test/text.ktx b/test/text.ktx new file mode 100644 index 0000000..05a6ae1 --- /dev/null +++ b/test/text.ktx @@ -0,0 +1,4 @@ +Okay **test**.name(yo).class(hi) //balls//.name(it) **lol** +This is [[a link]].href(#classics). I like to //fly//. + +okay