├── README.md
├── README.textmate-syntax.md
├── aa_ansiicolor.py
├── aa_macro.py
├── aa_macrov3.py
├── aagen
├── aagen-example.txt
├── aagen.README.md
├── acrobase.txt
├── acroclass.py
├── authoring.md
├── changelog.md
├── embrace-example.py
├── enhancement.md
├── expected.html
├── feature-list.md
├── files.md
├── forvariable.txt
├── genquickref.sh
├── leo.png
├── mactest.txt
├── martomac.README.md
├── martomac.py
├── mtm.md
├── mycustommd.mac
├── plugin_demo.c
├── qr_html.txt
├── qr_markdown.txt
├── quickref.html
├── quickref.md
├── quickref.txt
├── tease.png
├── test.gif
├── test.jpg
├── test.png
├── test_aa_macro.py
├── testing.README.md
├── textmate-syntax.png
├── textmate-syntax.txt
├── todo.md
├── unisample.txt
├── unknown.syntax
└── users-guide.md
/README.md:
--------------------------------------------------------------------------------
1 | # [aa\_macro.py](aa_macro.py) -- class macro() -- BETA
2 |
3 | > Also see: [project file descriptions](files.md)
4 |
5 | 
6 |
7 | > Sometimes a [demo](http://ourtimelines.com/aamacropreview.html) is
8 | worth a thousand words. Or, read on:
9 |
10 | I don't use WYSIWYG HTML/CSS editors, as they may generate sub-par code,
11 | may break with any application or library or operating system upgrade,
12 | and in the end, I have zero control over where and when they break, or
13 | any particular assurance I can easily correct the problem\(s\) if and
14 | when they occur. So something to make generation of HTML and CSS easier,
15 | of which I had direct control... and which depended upon nothing outside
16 | of Python itself... that really seemed like a fine idea to me. And so
17 | class `macro()` was born. :\)
18 |
19 | This project provides a means for me, and anyone else who wants to, to
20 | generate HTML or other types of text documents using Python as the
21 | intermediary engine. There are no external dependencies that aren't
22 | actually part of the latest Python 2-series distribution. \(This began as
23 | Python-2 project. There is a development Python-3 version in the repo as
24 | well, and again, there are no non-distribution-Python dependencies.\)
25 |
26 | Consequently the class is relatively lightweight and trivially installed
27 | — just drop the `aa_macro.py` (or `aa_macrov3.py`) file in and you're done. You'll
28 | probably want the [aagen utility](aagen) as well if you're looking to
29 | just make documents, but you don't need it if you're going to be using
30 | the class directly in your own Python applications; [aagen](aagen) is
31 | basically just a command-line friendly wrapper around the class.
32 |
33 | > Please don't be intimidated by the number of files in the repo; everything
34 | except [aa_macro.py](aa_macro.py) is either documentation, sample files,
35 | part of the unit tests, or related to a markdown-to-macro
36 | format converter utility.
37 |
38 | The benefit is conceptually like markdown — just feed in a text file
39 | and get back HTML — but `macro()` is much, much
40 | more powerful.
41 |
42 | `macro()` is a terrific solution to a very wide range of HTML formatting
43 | tasks and challenges. You can do anything from format a simple paragraph
44 | to generate a complete manual with indexes, table of contents,
45 | footnotes, completely custom styles and more.
46 |
47 | `macro()` can be extended or altered in any way by external plug-ins.
48 |
49 | One of the reasons that `macro()` is more powerful is that although the
50 | idea is similar in that it enables you to generate HTML easily and that
51 | it can certainly be easily readable if used in the simple ways such as
52 | one uses markdown, it does not embrace the idea that a text source file
53 | should look like an unmarked file, or that functionality should be
54 | sacrificed because complex functionality might not be as readable.
55 |
56 | Consider: have you seen much markdown actually displayed as text?
57 | Personally, I don't see that characteristic as valuable in and of itself -- by
58 | far, based on how it is used, the more valuable characteristic is
59 | that it is *readable*, which is not the same thing at all as "looks like
60 | unmarked text." You can approach `macro()` the same way, aiming at the
61 | same types of markup, and it'll be perfectly readable -- it just won't
62 | look like it is unmarked.
63 |
64 | Here are some comparisons relevant to markdown that demonstrate
65 | the readability of basic markup:
66 |
67 | Desired Result | Markdown | macro\(\)
68 | -------------- | -------- | -------
69 | Italics | \*verbiage\* | \[i verbiage\]
70 | Bold | \*\*verbiage\*\* | \[b verbiage\]
71 | Paragraph | verbiage | \[p verbiage\]
72 | List | \* item1
\* item2 | \[ul item1,item2\]
*or, if you prefer,*
\[ul
item1,
item2
\]
73 |
74 | Use is trivial:
75 |
76 | ```python
77 | from aa_macro import *
78 | mod = macro()
79 | textToProcess = '[b Boldly said]' # results in Boldly said
80 | processedText = mod.do(textToProcess)
81 | ```
82 |
83 | That's basically all there is to it.
84 |
85 | Here's a quick introduction to the concept of a style in the context of
86 | `macro()`. You define a style by giving it a name, and then filling it
87 | with... goodies. :\) It has a *special* goodie, the `[b]` tag (no parameters),
88 | which fills in with the content you feed the style. Here is the
89 | idea in a nutshell:
90 |
91 | [style hi Why hello, [b], how are you?]
92 |
93 | Which you use like this...
94 |
95 | {hi Ben}
96 |
97 | ...which would in turn result in:
98 |
99 | Why hello, Ben, how are you?
100 |
101 | You can also pass multiple parameters, splitting them up any way you like; commas, vbars, etc.
102 |
103 | What this means is that you can easily create an enormous range of text macros, even
104 | to the point of completely replacing the standard ones supplied in class `macro()`.
105 |
106 | For instance, `macro()` provides `[i textToItalicize]` for italic text. But you can do this...
107 |
108 | [style i [b]]
109 |
110 | ...and then use the following, which doesn't use the built-in:
111 |
112 | {i textToItalicize}
113 |
114 | Once the style is defined the way you want it, it does all the work. So you can customize it
115 | any way you want to. You could easily build a set of styles that would give you correct
116 | HTML for any revision of the HTML spec. The flexibility of this approach is very high.
117 |
118 | From here, we step into far more powerful \(and interesting, I think\)
119 | areas of formatting and then some blatantly tricky use of styles as well.
120 |
121 | I'll give one example \(Okay, two examples, thanks a lot, Blake :metal:\) here using several features;
122 | but `macro()` offers a wide range of features beyond this, so don't
123 | think for a moment that this in any way represents a limit on what you can do.
124 |
125 | [local chapter Introduction to the Work]
126 | [style h1
[v [b]]
]
127 |
128 | {h1 chapter}
129 |
130 | The first line sets a local variable named chapter to "Introduction to the Work"
131 |
132 | The second line:
133 |
134 | * creates a style that uses \[v \[b\]\] to produce the content of the variable
135 | name which is provided as the body of the style.
136 | * wraps that in <h1> and </h1> tags
137 |
138 | The third line invokes the style with the name of the variable.
139 |
140 | This produces the following HTML:
141 |
142 | Introduction to the Work
143 |
144 | The utility of such a thing is that first, the chapter name can now be
145 | referenced anywhere, and changed at any time, because it is a variable
146 | \(a local... globals are supported as well\); while the h1 style shows how
147 | you can wrap anything - in this case the content of the variable name
148 | passed in - in any other tags or encodings you wish. Second, it is
149 | *much* more concise than what you'd have to write using raw HTML and
150 | CSS. Third, like CSS, you can pack away your styles and build a library,
151 | or libraries, of tools that do exactly what you want them to.
152 |
153 | ## A \(much\) more complex example
154 |
155 | So, my friend looked at an earlier version of this readme, and he, in a
156 | fit of Perl-like cognition, says to me:
157 |
158 | "...so rather than this: `{h1 chapter}` I'd like `{h1 $chapter}`"
159 |
160 | Personally, not my thing. However. Here's a style that distinguishes between `$chapter`
161 | and `chapter`, treating the former as a variable name to resolve, and the latter as a literal \(you can
162 | break styles over multiple lines after the style name and/or within any content destined for output\)...
163 |
164 | [style v
165 | [if [slice :1,[b]] $ [v [slice 1:,[b]]]]
166 | [else [slice :1,[b]] $ [b]]]
167 |
168 | ...so now you can do this...
169 |
170 | `{v chapter}` which produces "chapter"
171 | ...or this...
172 | `{v $chapter}` which produces "Introduction to the Work"
173 |
174 | With style v in the can, so to speak, now we can write the h1 style this way:
175 |
176 | [style h1 {v [b]}
]
177 |
178 | So now to use h1 you could write:
179 |
180 | `{h1 $chapter}` which would get you....
181 |
182 | Introduction to the Work
183 |
184 | ...as opposed to:
185 |
186 | `{h1 chapter}` which gets you...
187 |
188 | chapter
189 |
190 | And, now that you have the v style written, you can use it anywhere:
191 |
192 | [style italic [i {v [b]}]]
193 |
194 | or, more concisely...
195 |
196 | [style i [i {v [b]}]]
197 |
198 | ...to be used like this \(either style i or style italic work as of now\):
199 |
200 | `{i chapter}` which gets you "*chapter*"
201 | `{i $chapter}` which gets you "*Introduction to the Work*"
202 |
203 | Same friend: "So what if I want to feed in `$chapter` as a literal?"
204 |
205 | One way is with an escape mechanism for $. Here's how to do
206 | that using the HTML entity for "$":
207 |
208 | [style $ $]
209 |
210 | Now we can do these things:
211 |
212 | `{i {$}chapter}` = "*$chapter*"
213 | `{i chapter}` = "*chapter*"
214 | `{i $chapter}` = "*Introduction to the Work*"
215 |
216 | ## Too Terse?
217 |
218 | Oh, say it isn't so\! Well, it probably is. But it doesn't matter,
219 | really, because *you* can make it read and work any way you want. Let's
220 | just go after that `[v]` idiom. To refresh your memory, `[v]` pulls a
221 | local variable by name \(or a global if there is no local\) and returns
222 | the content. I found `[v]` to be sufficient, being just that kind of
223 | terse, annoying person. But you, perhaps *you* would like something a
224 | bit more... explicit. And here we find the gold, as it were:
225 |
226 | Starting from ground zero, where this functionality exists:
227 |
228 | [v variableName]
229 |
230 | This...
231 |
232 | [style read-variable [v [b]]]
233 |
234 | ...creates the ability to do this:
235 |
236 | {read-variable variableName}
237 |
238 | Not so terse now, is it?
239 |
240 | You can re-define *anything*. Make `macro()` your own in every way. It's easy and
241 | it's fun. Well, I think it's fun. But again, I'm a little odd. :\)
242 |
243 | ## More
244 |
245 | At the top of the class in the [aa_macro.py](aa_macro.py) file, all the
246 | various features are described in what amounts to a quick-reference
247 | style format. At the end of the import library containing the class
248 | there are a series of examples that will execute if you simply type this
249 | at the command line:
250 |
251 | python aa_macro.py
252 |
253 | Finally, and much more completely, there is the [user guide](users-guide.md),
254 | as well as the [quick reference](quickref.md)
255 |
256 | Enjoy.
257 |
--------------------------------------------------------------------------------
/README.textmate-syntax.md:
--------------------------------------------------------------------------------
1 | # Textmate \(and presumably Github\) compatible syntax definition
2 |
3 | [textmate-syntax.txt](textmate-syntax.txt) is what you need to
4 | put in a Textmate bundle in order to display `macro()` source
5 | with syntax highlighting.
6 |
7 | Keep in mind that what this does is set up some of textmate's
8 | pre-defined classes to go along with `macro()` syntax; the coloring
9 | itself is matched to those classes in Textmate's preferences,
10 | under "Fonts and Colors."
11 |
12 | Here's how I have mine set up:
13 |
14 | 
15 |
16 | ## Environment
17 |
18 | These are the circumstances under which I developed this syntax file:
19 |
20 | OS X 10.6.8, Mac Pro Dual Xeon 8-core, Textmate Version 1.5.11 (1635)
21 |
22 | Note there are later versions of both Textmate and OS X, and using those may require
23 | some additional work.
24 |
25 | Sadly, Apple broke the Mac operating system so badly as of OS X 10.9 that Textmate 1.x will no longer work, so your only option there is to go with 2.x. Gotta love Apple, charging directly into the future —
26 | right over your software investment. Sheesh.
27 |
--------------------------------------------------------------------------------
/aagen:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python
2 |
3 | import sys
4 | import os
5 | from aa_macro import *
6 |
7 | report = False
8 | suppress = False
9 | nocolor = False
10 | genoutput = True
11 |
12 | try:
13 | from aa_ansiicolor import *
14 | except:
15 | ac = None
16 | else:
17 | ac = htmlAnsii()
18 |
19 | def lx(s,color):
20 | global ac
21 | global nocolor
22 | if ac != None:
23 | if nocolor == False:
24 | s = ac.c(s,color)
25 | return s
26 |
27 | argv = sys.argv[1:]
28 |
29 | def optr(oa,ob,p,c):
30 | flgcolor = 'purple' # flag color
31 | optcolor = 'white' # option color
32 | parcolor = 'green' # parenthesis color
33 | prmcolor = 'yellow' # parameter color
34 | barcolor = 'white' # 'or' bar color
35 | comcolor = 'green' # comment color
36 | s = ''
37 | s += 4 * ' '
38 | pm = p
39 | if pm != '': pm = ' ' + pm
40 | if p != '': p = ' ' + lx(p,prmcolor)
41 | l = len('%s %s%s%s%s%s' % ('(','-'+oa,'|','--'+ob,pm,')'))
42 | pad = (28 - l) * ' '
43 | x = '%s %s%s%s%s%s%s' % (lx('(',parcolor),lx('-'+oa,flgcolor),lx('|',barcolor),lx('--'+ob,flgcolor),p,lx(')',parcolor),pad)
44 | s += '%s %s' % (x,lx(c,comcolor))
45 | print s
46 |
47 | def usage():
48 | print "Usage"
49 | print "-------------------------------------------------------------------------------"
50 | print "aagen inputFileName"
51 | optr('f','file','outputFileName','Write output to file')
52 | optr('r','report','','Report input and output text lengths')
53 | optr('s','suppress','','Suppress stdout usage printout when error')
54 | optr('nc','ncolor','','Don\'t use console color (color requires aa_ansiicolor)')
55 | optr('ng','nogen','','Don\'t generate output')
56 | optr('o','open','','Send output to OS X HTML browser')
57 | optr('i','include','includeFileName','Process this file first')
58 | print "-------------------------------------------------------------------------------"
59 |
60 | def error(msg):
61 | global c
62 | global suppress
63 | if suppress != True:
64 | usage()
65 | sys.stderr.write(lx('ERROR: ','red') + lx(msg,'yellow')+'\n')
66 | raise SystemExit
67 |
68 | def idarg(arg,match):
69 | alen = len(match)
70 | if arg[:alen] == match:
71 | return True
72 | return False
73 |
74 | ofn = ''
75 | ifn = ''
76 | mfn = ''
77 | off = False
78 | mff = False
79 | mmff = False
80 | gfn = False
81 | osx = False
82 | noparms = True
83 | for arg in argv:
84 | if off == True:
85 | ofn = arg
86 | off = False
87 | if arg != '':
88 | gfn = True
89 | else:
90 | error('No filename specified after "--file or -f"')
91 | elif mff == True:
92 | mfn = arg
93 | mff = False
94 | if arg != '':
95 | mmff = True
96 | else:
97 | error('No filename specified after "--include or -i"')
98 | elif idarg(arg,'--file') == True or idarg(arg,'-f') == True:
99 | off = True
100 | noparms = False
101 | elif idarg(arg,'--open') == True or idarg(arg,'-o') == True:
102 | osx = True
103 | noparms = False
104 | elif idarg(arg,'--include') == True or idarg(arg,'-i') == True:
105 | mff = True
106 | noparms = False
107 | elif idarg(arg,'--report') == True or idarg(arg,'-r') == True:
108 | report = True
109 | noparms = False
110 | elif idarg(arg,'--suppress') == True or idarg(arg,'-s') == True:
111 | suppress = True
112 | noparms = False
113 | elif idarg(arg,'--nogen') == True or idarg(arg,'-ng') == True:
114 | genoutput = False
115 | noparms = False
116 | elif idarg(arg,'--nocolor') == True or idarg(arg,'-nc') == True:
117 | nocolor = True
118 | else:
119 | noparms = False
120 | ifn = arg
121 | if ifn == '':
122 | error('No inputFileName supplied')
123 |
124 | if noparms == True:
125 | usage()
126 | raise SystemExit
127 |
128 | if ifn == '':
129 | error('inputFileName not supplied')
130 |
131 | try:
132 | ifh = open(ifn)
133 | except:
134 | error('can\'t open inputFileName "%s" for reading' % (ifn,))
135 |
136 | try:
137 | inputText = ifh.read()
138 | except:
139 | try:
140 | ifh.close()
141 | except:
142 | pass
143 | error('Unable to read inputFileName "%s"' % (ifn,))
144 |
145 | if gfn == True:
146 | try:
147 | fh = open(ofn,'w')
148 | except:
149 | try:
150 | ifh.close()
151 | except:
152 | pass
153 | error('Cannot open outputFileName "%s" for writing' % (ofn,))
154 |
155 | icontent = ''
156 | if mmff == True:
157 | try:
158 | mfh = open(mfn)
159 | except:
160 | error('Cannot open includeFileName "%s" for reading' % (mfn,))
161 | else:
162 | try:
163 | icontent = mfh.read()
164 | except:
165 | try:
166 | mfh.close()
167 | except:
168 | pass
169 | error('Cannot read includeFileName "%s"' % (mfn,))
170 | else:
171 | try:
172 | mfh.close()
173 | except:
174 | error('Could not close includeFileName "%s"' % (mfn,))
175 |
176 | il = len(inputText)
177 | if icontent != '':
178 | mod = macro()
179 | mod.do(icontent)
180 | o = mod.do(inputText)
181 | else:
182 | o = str(macro(inputText))
183 | ol = len(o)
184 |
185 | if gfn == True:
186 | try:
187 | fh.write(o)
188 | except:
189 | error('Could not write outputFileName "%s"' % (ofn,))
190 | try:
191 | fh.close()
192 | except:
193 | pass
194 | try:
195 | fh.close()
196 | except:
197 | error('Could not close outputFileName "%s"' % (ofn,))
198 | else:
199 | try:
200 | if genoutput == True:
201 | sys.stdout.write(o)
202 | except:
203 | error('Could not write to stdout')
204 |
205 | if osx == True:
206 | if gfn == True:
207 | cmd = 'open "%s"' % (ofn)
208 | os.system(cmd)
209 |
210 | if report == True:
211 | print lx(' Read ','green') + lx('%d' % (il,),'white')+lx(' characters','green')
212 | print lx('Generated ','green') + lx('%d' % (ol,),'white')+lx(' characters','green')
213 |
--------------------------------------------------------------------------------
/aagen-example.txt:
--------------------------------------------------------------------------------
1 | [style html [b][nl]]
2 | [style body [nl][b][nl]]
3 | [style head [nl][b]]
4 | [style title [nl][b][nl]]
5 | [style hi Why hello, [b], how are you?]
6 |
7 | {html {head {title aagen Example}}
8 | {body
9 | [p
10 | {hi Ebenezer}
11 | ]
12 | }}
13 |
--------------------------------------------------------------------------------
/aagen.README.md:
--------------------------------------------------------------------------------
1 | # [aagen](aagen)
2 |
3 | [aagen](aagen) is a command line tool to take a source input file
4 | formatted for the `macro()` processor, and generate the results to a
5 | file or to the stdout stream.
6 |
7 | [aagen](aagen) requires aa_macro.py
8 |
9 | [aagen](aagen) can use aa_ansiicolor.py if it is present to do syntax
10 | highlighting on its errors and usage outputs. If this import library is
11 | not present, [aagen](aagen) simply won't use color.
12 |
13 | Invocation; use `aagen` if aagen is in the current path but not the
14 | current directory, or `./aagen` if aagen is in the current directory.
15 |
16 | An example file is provided:
17 |
18 | aagen-example.txt
19 |
20 | You can utilize the example file this way:
21 |
22 | aagen aagen-example.txt
23 | aagen aagen-example.txt -f aagen-example.html
24 |
25 | ...or...
26 |
27 | ./aagen aagen-example.txt
28 | ./aagen aagen-example.txt -f aagen-example.html
29 |
30 | Type `aagen` or `./aagen` by itself for a listing of the available options.
31 |
32 | ## Quick Reference Generation
33 |
34 | The repo includes a quick reference file, [quickref.txt](quickref.txt)
35 |
36 | This file contains the "meat" of the quick reference, which is
37 | designed using styles. It can be generated as either markdown,
38 | [as you see it here](quickref.md), or as HTML,
39 | [as you se it here.](quickref.html).
40 |
41 | The way this is done is to use a different set of styles, which define
42 | what the styles in [quickref.txt](quickref.txt) actually mean. Here are
43 | the two command lines:
44 |
45 | aagen -i qr_html.txt -f quickref.html quickref.txt
46 | aagen -i qr_markdown.txt -f quickref.md quickref.txt
47 |
48 | The first one generates an HTML output file, while the second
49 | generates a markdown file.
50 |
51 | This serves as a small demonstration of just how flexibly you can
52 | generate output using styles.
53 |
54 |
--------------------------------------------------------------------------------
/acroclass.py:
--------------------------------------------------------------------------------
1 | import re
2 |
3 | class core(object):
4 | # Project Info:
5 | # =============
6 | # Written by: fyngyrz - codes with magnetic needle
7 | # Incep date: November 24th, 2018
8 | # Last Update: January 28th, 2019 (this code file only)
9 | # Environment: Python 2.7
10 | # Source Files: acroclass.py, acrobase.txt
11 | # Tab Spacing: Set to 4 for sane readability of Python source
12 | # Security: Suitable for benign users only (IOW, me.)
13 | # Purpose: Creates informative tag wraps around
14 | # all-caps terms in the source text. Written
15 | # to support use of on soylentnews.org
16 | # License: None. Use as you will. PD, free, etc.
17 | # Dependencies: standard Python re import library
18 | # ----------------------------------------------------------
19 |
20 | def version_set(self):
21 | return('0.0.7 Beta')
22 |
23 | def __init__(self, detectterms=True, # disable class.makeacros() = False
24 | numberterms=False, # disable detecting terms incorporating numbers
25 | detectcomps=True, # detect electronic components
26 | iglist=[], # terms to ignore
27 | acrofile='acrobase.txt', # file to load term expansions from
28 | editor=False, # use editor's marks
29 | inquotes=False, # use editor's marks only within blockquote spans
30 | astyle='', # style content for tags
31 | edpre = '', # editor prefix
32 | edpost = ''): # editor postfix
33 | self.version = self.version_set()
34 | self.detectterms = detectterms
35 | self.numberterms = numberterms
36 | self.detectcomps = detectcomps
37 | self.acrofile = acrofile
38 | self.setstyle(astyle)
39 | self.igdict = {}
40 | self.undict = {}
41 | self.editor = editor
42 | self.inquotes = inquotes
43 | self.inspan = 0
44 | self.edpre = edpre
45 | self.edpost = edpost
46 | self.acros = {}
47 | self.rmlist = []
48 | self.relist = []
49 | self.errors = u'' # note that errors are unicode strings!
50 | self.setacros(acrofile)
51 | self.geniglist(iglist)
52 |
53 | def setstyle(self,astyle):
54 | if astyle == '':
55 | self.astyle = astyle
56 | else:
57 | self.astyle = ' style="%s"' % (astyle)
58 |
59 | # Generate ignore list, remove items from main list
60 | # -------------------------------------------------
61 | def geniglist(self,iglist):
62 | for el in iglist:
63 | el = str(el).upper()
64 | self.igdict[el] = True
65 | try:
66 | del self.acros[el]
67 | except:
68 | pass
69 |
70 | # Convert a unicode string to an ASCII string, replacing any
71 | # characters > 127 with the appropriate character entity.
72 | # That in turn makes the text compatible with the macro
73 | # processor, as character entities are 100$ ASCII.
74 | # ----------------------------------------------------------
75 | def makeascii(self,text):
76 | o = ''
77 | for i in range(0,len(text)):
78 | try:
79 | c = text[i].encode("ascii")
80 | o += c
81 | except:
82 | o += '{:d};'.format(ord(text[i]))
83 | return o
84 |
85 | # Convert HTML character entities into unicode
86 | # --------------------------------------------
87 | def subents(self,text):
88 | state = 0 # nothing detected
89 | accum = u''
90 | o = u''
91 | for c in text:
92 | if state == 0: # nothing as yet?
93 | if c == u'&': # ampersand?
94 | state = 1 # ampersand!
95 | else:
96 | o += c
97 | elif state == 1: # ampersand found?
98 | if c == u'#': # hash?
99 | state = 2 # hash!
100 | accum = u'' # clear accumulator
101 | else: # not a hash, so not an entity encoding
102 | state = 0 # abort
103 | o += u'&'+c # flush char, done
104 | elif state == 2: # expecting digits or terminating semicolon
105 | if c.isdigit(): # digit?
106 | accum += c # add it to accumulator if so
107 | elif c == u';': # terminating
108 | s = u'\\U%08x' % (int(accum))
109 | ss= s.decode('unicode-escape')
110 | o += ss
111 | state = 0
112 | else: # bad encoding?
113 | o += u''
114 | o += accum
115 | state = 0
116 | return o
117 |
118 | # Read term expansion file into memory
119 | # ------------------------------------
120 | def setacros(self,acrofile):
121 | try:
122 | with open(acrofile) as fh:
123 | self.acrobase = fh.read()
124 | except Exception,e:
125 | self.acrobase = u''
126 | self.errors += u'failed to read file'+str(e)+u'\n'
127 | else:
128 | self.acrobase = self.acrobase.replace(u'"',u'"') # can't have quotes in abbr tags
129 | self.makedict()
130 |
131 | # Test string for integer representation
132 | # --------------------------------------
133 | def chkint(self,text):
134 | try:
135 | n = int(text)
136 | except:
137 | return False
138 | return True
139 |
140 | # Create dictionary from the acronym / abbreviation file contents
141 | # ---------------------------------------------------------------
142 | def makedict(self):
143 | self.acros = {}
144 | linecounter = 1
145 | l1 = self.acrobase.split(u'\n')
146 | edpr = u''
147 | edpo = u''
148 | if self.editor == True:
149 | edpr = self.edpre
150 | edpo = self.edpost
151 | for el in l1:
152 | if len(el) != 0:
153 | if el[0:1] != u'#':
154 | try:
155 | veri = True
156 | key,alternate,expansion = el.split(u',',2)
157 | if expansion.find('<') != -1: veri = False
158 | if expansion.find('>') != -1: veri = False
159 | if veri == True:
160 | if key == '*': # if this is a component designator
161 | if self.detectcomps == True:
162 | self.rmlist.append(expansion)
163 | self.relist.append(alternate)
164 | else:
165 | pass
166 | elif self.numberterms == False and self.chkint(key) == True:
167 | pass
168 | else: # normal term definition
169 | term = key
170 | if alternate != u'':
171 | term = alternate
172 | if self.acros.get(key,'') != '':
173 | self.errors += u'Duplicate ACRO key: '+ unicode(key) + u'\n'
174 | alist = expansion.split('|')
175 | if len(alist) == 1:
176 | self.acros[key] = expansion
177 | else:
178 | alist.sort()
179 | s = u''
180 | n = 1
181 | for el in alist:
182 | if n != 1: s = s + u' '
183 | s = s + u'(' + unicode(str(n)) + u'): '+unicode(str(el))
184 | n += 1
185 | self.acros[key] = s
186 | else:
187 | self.errors += u'< or > found in ACRO: '+ unicode(key) + u'\n'
188 | except Exception,e:
189 | self.errors += u'line '+str(linecounter)+u': '
190 | self.errors += u'"'+unicode(el)+u'"\n'+unicode(str(e))
191 | linecounter += 1
192 |
193 | # Match term against component encodings
194 | # --------------------------------------
195 | def compmatch(self,term):
196 | if self.detectcomps == False: return term
197 | if self.igdict.get(term,False) == True: return term
198 | if self.isnumeric(term) == False: # if not fully numeric
199 | rmatch = False
200 | ren = 0
201 | edpr = u''
202 | edpo = u''
203 | if self.editor == True:
204 | edpr = self.edpre
205 | edpo = self.edpost
206 | for el in self.relist:
207 | ln = len(el)
208 | el = el + '\d*'
209 | if re.match(el,term):
210 | try:
211 | n = int(term[ln:])
212 | except: # not a number, bail
213 | pass
214 | else:
215 | comp = self.rmlist[ren]
216 | ell = comp.split('|')
217 | smark = edpr
218 | emark = edpo
219 | if self.inquotes == True:
220 | if self.inspan == 0:
221 | smark = u''
222 | emark = u''
223 | if len(ell) == 1:
224 | string = '%s' % (self.astyle,smark,comp,n,emark,term)
225 | else: # multiple elements
226 | x = 1
227 | smark = edpr
228 | emark = edpo
229 | if self.inquotes == True:
230 | if self.inspan == 0:
231 | smark = u''
232 | emark = u''
233 | string = ''+term+''
240 | return string
241 | ren += 1
242 | return term
243 |
244 | # Explicit match against numerals 0...9
245 | # -------------------------------------
246 | def isnumeric(self,text):
247 | for c in text:
248 | if c < u'0' or c > u'9': return False
249 | return True
250 |
251 | # Conversion including translation to unicode
252 | # -------------------------------------------
253 | def a2u(self,text): # ASCII in
254 | if type(text) is not str:
255 | self.errors += u'class function a2u() requires ASCII input\n';
256 | return u''
257 | return self.makeacros(unicode(text)) # generate tags, unicode out
258 |
259 | def a2a(self,text): # ASCII in
260 | if type(text) is not str:
261 | self.errors += u'class function a2a() requires ASCII input\n';
262 | return u''
263 | text = self.makeacros(unicode(text)) # generate tags, unicode out
264 | return self.makeascii(text) # get back an entity-encoded string
265 |
266 | # Conversion including translation from unicode
267 | # ---------------------------------------------
268 | def u2a(self,text): # unicode in
269 | if type(text) is not unicode:
270 | self.errors += u'class function u2a() requires unicode input\n';
271 | return ''
272 | text = self.makeacros(text) # generate tags, ASCII out
273 | return self.makeascii(text) # convert to ASCII string
274 |
275 | def cleanbraces(self,text):
276 | text = text.replace('<','<')
277 | text = text.replace('>','>')
278 | return text
279 |
280 | def makeacros(self,text): # for compatibility only
281 | return self.u2u(text)
282 |
283 | # Convert all instances of TERM to TERM
284 | # where TERM is capAlpha or some combination of capAlpha and Numeric
285 | # This is unicode in, unicode out
286 | # --------------------------------------------------------------------
287 | def u2u(self,text):
288 | tlen = len(text)
289 | ccnt = 0
290 | if self.detectterms == False: return text
291 | if type(text) is not unicode:
292 | self.errors += 'class function makeacros() requires unicode input\n';
293 | return ''
294 | incaps = False
295 | accum = u''
296 | o = u''
297 | ctag = u''
298 | btag = u''
299 | wait = False
300 | wait2 = False
301 | for c in text: # iterate all characters
302 | ccnt += 1
303 | if c == u'<':
304 | wait = True # if within an HTML tag, don't bother
305 | ctag = u'' # reset abbr detector
306 | btag = u'' # reset blockquote detector
307 | elif c == u'>': wait = False
308 | ctag += c.lower()
309 | btag += c.lower()
310 | if btag[:11] == u'
320 | ctag = u''
321 | elif ctag[:6] == u'= u'A' and c <= u'Z') or (c >= u'0' and c <= u'9')):
325 | accum += c
326 | else: # not a cap now
327 | if len(accum) > 1:
328 | taccum = self.acros.get(accum,accum)
329 | if taccum == accum: # not found
330 | if self.isnumeric(accum) == False: # if not fully numeric
331 | taccum = self.compmatch(accum)
332 | if taccum == accum: # still not found
333 | if self.igdict.get(taccum,'') == '':
334 | self.undict[taccum] = 1 # we don't know this one
335 | else: # we found it
336 | if self.editor == True:
337 | smark = self.edpre
338 | emark = self.edpost
339 | else:
340 | smark = u''
341 | emark = u''
342 | if self.inquotes == True:
343 | if self.inspan == 0:
344 | smark = u''
345 | emark = u''
346 | taccum = '%s' % (self.astyle,smark,taccum,emark,accum)
347 | accum = taccum
348 | accum += c
349 | o += accum
350 | accum = u''
351 | else: # 1 or 0
352 | o += accum
353 | accum = u''
354 | o += c
355 | if accum != u'': # any pending on end of post?
356 | if len(accum) > 1:
357 | taccum = self.acros.get(accum,accum)
358 | if taccum == accum:
359 | if self.isnumeric(taccum) == False:
360 | taccum = self.compmatch(accum)
361 | if taccum == accum: # still not found
362 | if self.igdict.get(taccum,'') == '':
363 | self.undict[taccum] = 1 # we don't know this one
364 | else:
365 | if self.editor == True:
366 | smark = self.edpre
367 | emark = self.edpost
368 | else:
369 | smark = u''
370 | emark = u''
371 | if self.inquotes == True:
372 | if self.inspan == 0:
373 | smark = u''
374 | emark = u''
375 | taccum = '%s' % (self.astyle,smark,taccum,emark,accum)
376 | accum = taccum
377 | o += accum
378 | else: # 1 or 0
379 | o += accum
380 | return o
381 |
--------------------------------------------------------------------------------
/authoring.md:
--------------------------------------------------------------------------------
1 | # Authoring in Macro\(\)
2 |
3 | This is a collection of ideas and approaches that may be interesting with
4 | regard to authoring using `Macro()`.
5 |
6 | ## Style definition
7 |
8 | ### Making a Style Definition Disappear Completely
9 |
10 | It aids clarity to place each style on its own line. However,
11 | conceptually, the newline at the end of the line is *outside*
12 | the style, and so ends up in the resulting output. The way to
13 | avoid this is to add two spaces to the end of any line that
14 | closes a style definition. `macro()` will see this and "eat"
15 | both the two spaces and the subsequent newline.
16 |
17 | ### Defining Styles Over Multiple Lines
18 |
19 | You can define a style over multiple lines by placing two spaces at the
20 | end of each line. Here's a fun use of styles, where one of the styles is
21 | built over four lines for clarity, with interspersed lines used to
22 | separate the styles and content. The interspersed lines are simply two
23 | spaces and a newline; consequently, they are stripped out so they make
24 | perfect spacers.
25 |
26 | This is a set of styles that provides a way to created ordered lists
27 | with reference labels. The reason to do this is that references to the
28 | list items can always be to the correctly numbered item in the list,
29 | even if you add other items later.
30 |
31 | Style | Function
32 | ----- | --------
33 | \{oostyle\} | the list style, in this case number, colon, space, item.
34 | \{oo\} | instantiates the list, setting the list ordinal to zero.
35 | \{oi\} | manages the numbering and association with the item lable.
36 | \{oref\} | emplaces the actual number of the lable-referenced list item.
37 |
38 | ```
39 | [style oo [local lcount 0]]
40 |
41 | [style oostyle [v lcount]: [b]]
42 |
43 | [style oi [local lcount [add [v lcount] 1]]
44 | [splitcount 1][split [co],[b]]
45 | [dset lmem,[parm 0]:[v lcount]]
46 | {oostyle [parm 1]}]
47 |
48 | [style oref #[d lmem,[b]]]
49 |
50 | Foodieness
51 |
52 | {oo}
53 | {oi nut,line of nuttiness}
54 | {oi fruit,fruity line}
55 | {oi rock,stone-age line}
56 |
57 | Referring to item {oref fruit}, I prefer cherries.
58 | ```
59 |
60 | The output of the above is:
61 |
62 | ```
63 | Foodiness
64 |
65 | 1: line of nuttiness
66 | 2: fruity line
67 | 3: stone-age line
68 |
69 | Referring to item #2, I prefer cherries.
70 | ```
71 |
72 | This type of list generation also allows list splitting around content,
73 | as the list context does not end until the next list is instantiated.
74 |
75 | ```
76 | Foodiness
77 |
78 | {oo}
79 | {oi nut,line of nuttiness}
80 | {oi fruit,fruity line}
81 | {oi rock,stone-age line}
82 |
83 | Referring to item {oref fruit}, I prefer cherries. However...
84 |
85 | {oi spag,spaghetti}
86 | {oi shel,shells}
87 | {oi ling,linguini}
88 |
89 | ...when it comes to pasta, I prefer {oref lconv} over the others.
90 | ```
91 |
92 | The output of that is:
93 |
94 | ```
95 | Foodiness
96 |
97 | 1: line of nuttiness
98 | 2: fruity line
99 | 3: stone-age line
100 |
101 | Referring to item #2, I prefer cherries. However...
102 |
103 | 4: spaghetti
104 | 5: shells
105 | 6: linguini
106 |
107 | ...when it comes to pasta, I prefer #4 over the others.
108 | ```
109 |
110 | Coming back later, we can change the list to add an item up front,
111 | and the back-references will adjust themselves accordingly. Source:
112 |
113 | ```
114 | Foodiness
115 |
116 | {oo}
117 | {oi nut,line of nuttiness}
118 | {oi spop,soda}
119 | {oi fruit,fruity line}
120 | {oi rock,stone-age line}
121 |
122 | Referring to item {oref fruit}, I prefer cherries. However...
123 |
124 | {oi spag,spaghetti}
125 | {oi shel,shells}
126 | {oi ling,linguini}
127 |
128 | ...when it comes to pasta, I prefer {oref lconv} over the others.
129 | ```
130 |
131 | Now we get this:
132 |
133 | ```
134 | Foodiness
135 |
136 | 1: line of nuttiness
137 | 2: soda
138 | 3: fruity line
139 | 4: stone-age line
140 |
141 | Referring to item #3, I prefer cherries. However...
142 |
143 | 5: spaghetti
144 | 6: shells
145 | 7: linguini
146 |
147 | ...when it comes to pasta, I prefer #5 over the others.
148 | ```
149 |
150 | You can also use the \[fref\] and \[resolve\] built-ins to refer
151 | to things that have not yet been defined, like this:
152 |
153 | ```
154 | Foodiness
155 |
156 | Pay attention when I talk about pasta in items [fref l1], [fref l2]
157 | and [fref l3].
158 |
159 | {oo}
160 | {oi nut,line of nuttiness}
161 | {oi spop,soda}
162 | {oi fruit,fruity line}
163 | {oi rock,stone-age line}
164 |
165 | Referring to item {oref fruit}, I prefer cherries. However...
166 |
167 | {oi spag,spaghetti}
168 | {oi shel,shells}
169 | {oi ling,linguini}
170 |
171 | ...when it comes to pasta, I prefer {oref lconv} over the others.
172 | [resolve l1,{oref spag}]
173 | [resolve l2,{oref shel}]
174 | [resolve l3,{oref ling}]
175 | ```
176 |
177 | Which comes out as:
178 |
179 | ```
180 | Foodiness
181 |
182 | Pay attention when I talk about pasta in items #5, #6
183 | and #7.
184 |
185 | 1: line of nuttiness
186 | 2: soda
187 | 3: fruity line
188 | 4: stone-age line
189 |
190 | Referring to item #3, I prefer cherries. However...
191 |
192 | 5: spaghetti
193 | 6: shells
194 | 7: linguini
195 |
196 | ...when it comes to pasta, I prefer #5 over the others.
197 | ```
198 |
199 | Pretty spiffy, no? :\)
200 |
201 | ### Back-Referencing and Order of Definition
202 |
203 | Styles are not evaluated until they are used. This means that as long as all
204 | the styles involved are defined before they are invoked, either directly or
205 | within another style, they can be defined in any order. The allows you to
206 | create alphabetic-ordered style sets that in turn make it easier to find the
207 | style you are looking for.
208 |
209 | So:
210 |
211 | * Define styles in any order
212 | * Styles must be defined only before they are actually used
213 | * It's ok to reference one style within another before it is defined
214 | as long as the outermost style isn't actually invoked prior to any inner styles
215 | being defined.
216 |
217 | ## Namespaces
218 |
219 | Built-ins and styles have separate namespaces. As `{styleName` actually
220 | resolves to `[s styleName` in the processor, there's no conflict at all.
221 | So you can define finger-twisters like `[style b [b [b]]]` without any
222 | conflicts.
223 |
224 | Generally what this means in actual practice is:
225 |
226 | * you define your styles with `[s styleName]`
227 | * then, within your text
228 | * you use `{styleName}` to access your styles
229 | * you use `[builtInName]` to access built-ins
230 |
231 |
--------------------------------------------------------------------------------
/changelog.md:
--------------------------------------------------------------------------------
1 | # macro() BETA Changelog
2 |
3 | ### Note
4 |
5 | This log reflects changes to the aa_macro.py import library. Other changes
6 | such as to the associated utilities and sample files are not tracked here.
7 |
8 | ### Log
9 | 1.0.141
10 | * added quad-backtick code fencing
11 | * added [getc] built-in 'embeds=t' option
12 |
13 | 1.0.140
14 | * added [glosplit vName,splitSpec,contentToSplit]
15 | * [locsplit vName,splitSpec,contentToSplit] now sets vName_splitcount
16 |
17 | 1.0.139
18 | * added [locsplit vName,splitSpec,contentToSplit]
19 |
20 | ### Log
21 | 1.0.138
22 | * added semantic parameter to class for em and strong rather than i and b
23 |
24 | 1.0.137
25 | * added option astyle=CSSSTYLE to [term]
26 |
27 | 1.0.136
28 | * added [term CAPSTERM] which uses acroclass.py and acrobase.txt
29 |
30 | 1.0.135
31 | * added [ddelta YYYYMMDD YYYYMMDD]
32 |
33 | 1.0.134
34 | * added unicode pre- and post-processing
35 |
36 | 1.0.133
37 | * added [gstyle] and [style] secondary help strings
38 | * added [helpg2 stylename] and [helps2 stylename] to return secondary style help strings
39 |
40 | 1.0.132
41 | * added [gstyle] and [style] help strings
42 | * added [helpg stylename] and [helps stylename] to return style help strings
43 |
44 | 1.0.131
45 | * added (digits=decdigits,) option to [round value]
46 |
47 | 1.0.130
48 | * added [round value]
49 |
50 | 1.0.129
51 | * added eol=X option to wwrap
52 |
53 | 1.0.128
54 | * added optional notFound to [d]
55 |
56 | 1.0.127
57 | * bug in [crop] fixed
58 |
59 | 1.0.126
60 | * [crop] added
61 | * [collapse] added]
62 |
63 | 1.0.125
64 | * [center] now returns the text without padding if longer than center size
65 |
66 | 1.0.124
67 | * Added mode=1 to encrypt, decrypt. Larger random number range.
68 |
69 | 1.0.123
70 | * made the random number generator a little more robust
71 |
72 | 1.0.122
73 | * added again=1 to encrypt to enable double-locked box
74 |
75 | 1.0.121
76 | * added [datetime]
77 | * added [month]
78 | * added [ampm]
79 | * added [twelve]
80 |
81 | 1.0.120
82 | * added xlimit and dlimit parameters to class
83 |
84 | 1.0.119
85 | * added (mode=float,) to add, sub, div, mul
86 |
87 | 1.0.118
88 | * added [random]
89 |
90 | 1.0.117
91 | * added [br]
92 |
93 | 1.0.116
94 | * added loc_splashnum variable set on [splash] split iterations
95 |
96 | 1.0.115
97 | * added pre=, post=, inter=, and ntl= to [splash]
98 |
99 | 1.0.114
100 | * added [splash]
101 |
102 | 1.0.113
103 | * added locklipath invocation option
104 | * added lockwepath invocation option
105 |
106 | 1.0.112
107 | * rejiggered how debug data is tracked to allow for flexable reporting
108 |
109 | 1.0.111
110 | * added debug option and getdebug() method
111 |
112 | 1.0.110
113 | * added character-level tracking to error messages
114 |
115 | 1.0.109
116 | * added [encrypt]
117 | * added [decrypt]
118 |
119 | 1.0.108
120 | * added [save] and [gsave]
121 |
122 | 1.0.107
123 | * bug in tab expansion in [getc] fixed
124 |
125 | 1.0.106
126 | * improved c/c++,objective c parsing
127 | * added user-configurable syntax highlight colors for [getc]
128 |
129 | 1.0.105
130 | * corrected an error with [raw] and [graw] parsing
131 | * added var=varName option to [getc]
132 |
133 | 1.0.104
134 | * added global "aam_version" to return aa_macro version"
135 |
136 | 1.0.103
137 | * Error detection now includes line number of last opening tag
138 |
139 | 1.0.102
140 | * [url] will now accept nam=Localname without trailing comma
141 |
142 | 1.0.101
143 | * new options for [time]
144 | * new [int]
145 | * new [abs]
146 |
147 | 1.0.100
148 | * [limg] function added - improved on [locimg], [locimg] obsoleted
149 |
150 | 1.0.99
151 | * noembrace invocation switch added
152 | * noinclude invocation switch added
153 |
154 | 1.0.98
155 | * [url (sep=|,)(nam=Name,)(css=CSS,)(tgt=_target,)URLsepITEM]
156 |
157 | 1.0.97
158 | * [alphalead (trail=1,)content] added
159 | * [alphanumlead (trail=1,)content] added
160 |
161 | 1.0.96
162 | * [locimg] gets wpath and lpath options
163 |
164 | 1.0.95
165 | * (pathetic) sytax error detection added
166 |
167 | 1.0.94
168 | * [ol] gets [ol type=X] parameter
169 |
170 | 1.0.93
171 | * [ol] gets [ol start=N] parameter
172 |
173 | 1.0.92
174 | * cpp code highlighting (many more keywords)
175 |
176 | 1.0.91
177 | * oc code highlighting (minor diffs in keywords, @, etc.)
178 |
179 | 1.0.90
180 | * c code highlighting now highlights apparent preprocessor directives
181 |
182 | 1.0.89
183 | * small improvement in code highlighting where comments begin w/o whitespace
184 |
185 | 1.0.88
186 | * [getc] gets high=c code highlighting. Does not respect /* */ comments
187 |
188 | 1.0.87
189 | * [getc filename] added, loads c source file and converts to aa_macro
190 |
191 | 1.0.86
192 | * [load] and [gload] added, new forvariable.txt file in repo for testing
193 |
194 | 1.0.85
195 | * [capt] would not cap insig words at beginning of title, fixed
196 |
197 | 1.0.84
198 | * Added gstyleLib() utility function
199 |
200 | 1.0.83
201 | * [raw] and [graw] added
202 |
203 | 1.0.82
204 | * {stylename\ncontent} autoconverts to {stylename content}
205 | * \r\n and \n\r sequences are converted to \n to defeat windows, etc.
206 | * [s] and {stylename} can now handle multiple styles and single content
207 |
208 | 1.0.81
209 | * [ifol], [iful], [ol] and [ul] get istyle= and lstyle= options
210 |
211 | 1.0.80
212 | * HTML 4.01s span handling for [i], [u], [b] and [color] abstracted to globals
213 |
214 | 1.0.79
215 | * [if] and [else] style handling updated
216 |
217 | 1.0.78
218 | * [for] added
219 | * [in] added
220 |
221 | 1.0.77
222 | * [urlencode] finished
223 |
224 | 1.0.76
225 | * wtfm version of user manual goes live
226 | * error message on missing style for [locs] and [glos] improved
227 | * [switch] added
228 | * [case] added
229 | * [gt] and [lt] escapes added
230 | * [s], [glos] and [locs] all get sep= option for multiple style invocation
231 | * [asort] gets rev=1 option
232 | * [aisort] gets rev=1 option
233 | * [isort] gets rev=1 option
234 | * [lhsort] gets rev=1 option
235 | * [ssort] gets rev=1 option
236 | * [sisort] gets rev=1 option
237 | * [issort] gets rev=1 option
238 | * [hsort] gets rev=1 option
239 | * [dlist] gets fs=styleName and ls=styleName options
240 |
241 | 1.0.75
242 | * [eval] added
243 |
244 | 1.0.74
245 | * [wwrap] now has nohtml=1 option (plus [wwrap] entirely re-written)
246 |
247 | 1.0.73
248 | * [vinc] and [vdec] added
249 |
250 | 1.0.72
251 | * ? lol
252 |
253 | 1.0.71
254 | * [if] and [else] now have sep=X option
255 |
256 | 1.0.70
257 | * [th] and [nd] added
258 |
259 | 1.0.69
260 | * bug in [pythparse], fixed
261 |
262 | 1.0.68
263 | * [resolve] now has hex=1 option
264 |
265 | 1.0.67
266 | * [translate] now has pre=, post= and inter= options
267 |
268 | 1.0.66
269 | * [lsub] now has ci=1 option
270 |
271 | 1.0.65
272 | * [dlist] bugfix: non-style post= moved prior to inter=
273 |
274 | 1.0.64
275 | * [dlist] now has ntl=NTL option
276 |
277 | 1.0.63
278 | * [dlist] now has inter=INT option
279 |
280 | 1.0.62
281 | * [split] now sets local variable loc_splitcount
282 | * [replace] now has lf=1 option
283 |
284 | 1.0.61
285 | * [pythparse] added
286 |
287 | 1.0.60
288 | * Changed default color for nonkeyword python from 008800 to 00ff00
289 |
290 | 1.0.59
291 | * Bug in [postparse] with sub-line-sized code fragments fixed
292 |
293 | 1.0.58
294 | * [postparse] added
295 |
296 | 1.0.57
297 | * [hmap] added
298 |
299 | 1.0.56
300 | * [slit] got (wrap=1,) option
301 | * Pretty-printing now handles in-quotes
302 | * Pretty-printing now calls out keywords and stylenames
303 | * new built-in variables for all of the above (see docs)
304 |
305 | 1.0.55
306 | * [hlit], [vlit] and [slit] all got (format=1,) options
307 |
308 | 1.0.54
309 | * aa_macro no longer translates {stylename} to [s stylename], {} is now native
310 |
311 | 1.0.53
312 | * [slit] bug fixed
313 | * [hlit], [vlit] and [slit] translations now mapped through variables txl_...
314 |
315 | 1.0.52
316 | * [vlit] added
317 | * [slit] added
318 | * styling variables added that are used by [hlit], [vlit], and [slit]
319 |
320 | 1.0.51
321 | * [wepath] added, function of [locimg] changed (documented)
322 | * [global] and [local] now accept empty: [global varName] and [local varName] (documented)
323 | * [lsplit] added (documented)
324 | * [lsplit] understands a single [sp] as a command to split on ' '
325 | * [ljoin] added (documented)
326 | * [hlit] added (documented)
327 | * [usdate] added
328 |
329 | 1.0.50
330 | * [dlist] now understands local else global style wrapping (documented)
331 | * [crush] added (documented)
332 | * [clearl] added (documented)
333 | * [if] now accepts wrap as a syn for style (dcoumented)
334 |
335 | 1.0.49
336 | * [stripe (charset=chars,)content] added
337 | * [img] now produces empty title and alt tags to comply with HTML 4.01 strict
338 | * [style], [gstyle] and [lstyle] can now all be set to empty styles viz. [style styleName] with no content
339 | * unittests
340 | * users guide
341 | * quickref
342 |
343 | 1.0.48
344 | * [repeat] now understands any of [v], [gv], [lv] and [parm]
345 | * [listg (source=local,)listName] added
346 | * [stage (mode=float,)(digits=N)start end steps step] added
347 | * htodec,otodec,btodec,dtohex,dtooct,dtobin all have new digits=N option
348 | * [dlist \(style=styleName,\)] syn for [dlist \(wrap=styleName,\)]
349 | * unit tests updated
350 | * users guide
351 | * quickref
352 | * features
353 |
354 | 1.0.47 - December 13th, 2015
355 | * Bug in [eq] remediated
356 |
357 | 1.0.46 - December 13th, 2015
358 | * Bug in [gstyle] remediated
359 | * unit tests updated to test for above bug
360 |
361 | 1.0.45 - September 2nd, 2015
362 | * conditional styles now add output to processing stream:
363 | [if], [else], [even], [odd], [ne], [eq], [ifge], [ifle]
364 |
365 | 1.0.44 - September 1st, 2015
366 | * added style=styleName to all conditionals
367 |
368 | 1.0.43
369 | * removed auto-generation of newlines in [table] and [row]
370 | * added [vb] escape for |
371 |
372 | 1.0.42
373 | * added parms=X and posts=X to [dlist]
374 |
375 | 1.0.41
376 | * added [lcopy], [dcopy], [dkeys]
377 |
378 | 1.0.40
379 | * added [fref], [resolve]
380 |
381 | 1.0.39
382 | * added [date], [time], [sys]
383 |
384 | 1.0.38
385 | * added [ifge], [ifle]
386 |
387 | 1.0.37
388 | * added [lcc]
389 |
390 | 1.0.36
391 | * added [lsub]
392 |
393 | 1.0.35
394 | * added [include], [embrace], [lf], [expand]
395 |
396 | 1.0.34
397 | * added [lpop], [lpush] (synonym for append)
398 |
399 | 1.0.33
400 | * Moved the 'dothis' named parameter to first in class for simplest invocation
401 |
402 | 1.0.32
403 | * added [lslice]
404 |
405 | 1.0.31
406 | * added [llen]
407 |
408 | 1.0.30
409 | * added [hsort], [lhsort]
410 |
411 | 1.0.29
412 | * added [strip]
413 |
414 | 1.0.28
415 | * added [soundex]
416 |
417 | 1.0.27
418 | * added [count]
419 |
420 | 1.0.26
421 | * added [lc], [wc]
422 |
423 | 1.0.25
424 | * added [dtohex], [dtooct], [dtobin], [htodec], [otodec], [btodec]
425 |
426 | 1.0.24
427 | * added [gpage],[ghost]
428 |
429 | 1.0.23
430 | * added [max], [min]
431 |
432 | 1.0.22
433 | * added [ltol]
434 |
435 | 1.0.21
436 | * added [scase]
437 |
438 | 1.0.20
439 | * added [ssort], [sisort], [issort]
440 |
441 | 1.0.19
442 | * added [capw], [caps], [capt], [inter]
443 |
444 | 1.0.18
445 | * added (sep=X,) option to [push]
446 |
447 | 1.0.17
448 | * added [rjust],[ljust],[center]
449 | * added sep=X to [list] options
450 | * added sep=X to [ul] options
451 | * added sep=X to [ol] options
452 | * added sep=X to [iful] options
453 | * added sep=X to [ifol] options
454 |
455 | 1.0.16
456 | * added [find],[replace]
457 |
458 | 1.0.15
459 | * added [rstrip],[ord],[dup]
460 |
461 | 1.0.14
462 | * added [list],[lset],[e],[cmap],[translate],[asort],[aisort],[isort],[dlist],[append]
463 | * added [splitcount]
464 |
465 | 1.0.13
466 | * added [eq] to complement [ne]
467 |
468 | 1.0.12
469 | * added [locimg] to generate images with width and height set (jpg,png,gif)
470 | * added [lipath] to tell [locimg] where image file is in local filesystem
471 |
472 | 1.0.11
473 | * added [urlencode]
474 |
475 | 1.0.10
476 | * added [nl] for non-newline newline encoding in source (0x0a)
477 | * [img] now sets alt= as well as title=
478 |
479 | 1.0.9
480 | * added [bq] for HTML blockquote
481 |
482 | 1.0.8
483 | * added [mode] to control HTML output mode from source
484 | * added [back] to control HTML 4.01s background text color from source
485 | * added __str__() method for output of initially passed-in input in dothis
486 |
487 | 1.0.7
488 | * enhanced [img]
489 | * fixed bug in [web]
490 | * fixed bug in parser. Regex, sigh. Live by it, die by it.
491 | * if you end a line with two trailing spaces, object.do()
492 | will "eat" them, and the following newline, unles you
493 | set nodinner=True
494 |
495 | 1.0.6
496 | * added sanitize() utility to help make user input safer
497 | * sped up [roman numberString] when fed zero
498 | * added home page to class header
499 | * added polcies to class header
500 | * updated class documentation
501 |
502 | 1.0.5
503 | * added warning about parsing user input
504 | * wrote a walkthrough for generating roman numerals, consequently I...
505 | * added [upper textString]
506 | * added [lower textString]
507 | * added [roman numberString]
508 |
509 | 1.0.4
510 | * added advice on how to use examples
511 |
512 | 1.0.3
513 | * spiffied up the class docs a little
514 | * added [split splitSpec,contentToSplit]
515 | * added [parm N]
516 | * added to examples
517 |
518 | 1.0.2
519 | * added new URL link mechanism [a (tab,)URL(,LinkedText)]
520 | [link] and [web] will remain as per my "I will never
521 | take away something you may have used" policy, but
522 | [a] is really a better way to go about it now.
523 | * added escape for all commas [nc TextToBeEscaped]
524 | * added non-rendering [comment content] capability
525 | * added [slice sliceSpec,contentToSlice] capability
526 |
527 | 1.0.1
528 | * added HTML paragraphs as [p paragraph]
529 |
530 | 1.0.0
531 | * Initial Release
532 |
--------------------------------------------------------------------------------
/embrace-example.py:
--------------------------------------------------------------------------------
1 | # ---------------------------------
2 | # Example of plug-in module for the
3 | # aa_macro.py system that follows
4 | # the [embrace module] convention
5 | # ---------------------------------
6 |
7 | # The class MUST be named 'plug'
8 | # ------------------------------
9 | class plug(object):
10 | def __init__(self):
11 | self.settable()
12 |
13 | # This method MUST be named 'install'
14 | # This provides a reference to the parent class, macro()
15 | # ------------------------------------------------------
16 | def install(self,parent):
17 | self.parent = parent
18 |
19 | # [happy content] - extension of existing built-ins
20 | # -------------------------------------------------
21 | def happy_fn(self,tag,data): # an extension of macro() built-ins
22 | return data + ' :)'
23 |
24 | # [unhappy content] - extension of existing built-ins
25 | # ---------------------------------------------------
26 | def unhappy_fn(self,tag,data): # another extension of macro() built-ins
27 | return data + ' :('
28 |
29 | # [i content] - over-ride existing built-in, use instead of
30 | def i_fn(self,tag,data):
31 | return '' + data + ''
32 |
33 | # [dtcase] - dump the macro() notcase table
34 | def dtcase_fn(self,tag,data):
35 | o = ''
36 | for el in self.parent.notcase:
37 | if o != '':
38 | o += ', '
39 | o += el
40 | return o
41 |
42 | def settable(self):
43 | self.extensions = {
44 | 'happy' : self.happy_fn, # add new built-in 'happy'
45 | 'unhappy' : self.unhappy_fn, # add new built-in 'unhappy'
46 | 'i' : self.i_fn, # replace the 'i' built-in
47 | 'dtcase' : self.dtcase_fn, # access macro() varaibles
48 | }
49 |
50 | # This method MUST be named "gettable()"
51 | # --------------------------------------
52 | def gettable(self):
53 | return self.extensions
54 |
--------------------------------------------------------------------------------
/enhancement.md:
--------------------------------------------------------------------------------
1 | # Enhancing class `macro()`
2 |
3 | ## Externally Extending and/or Replacing [aa_macro.py](aa_macro.py) Functionalty
4 |
5 | See (extend-example.py)[extend-example.py] for a model of
6 | how to do everything you need to do.
7 |
8 | ## Changing [aa_macro.py](aa_macro.py) Itself
9 |
10 | Have an idea for a cool built-in? It can be very easy to do.
11 |
12 | A minimum of two tasks are typically involved. This is the 'hard"
13 | (cough) one:
14 |
15 | * In aa\_macro.py, search for the first occurance of `p_fn`
16 | * This is the "paragraph" built in. Look at it. All two lines of it.
17 |
18 | ```python
19 | def p_fn(self,tag,data):
20 | return ''+data+'
'
21 | ```
22 |
23 | * Incoming parameter **self**: obvious, or if not, put it in yours anyway
24 | * Incoming parameter **tag**: the tag that got you here, in this case `p`
25 | * Incoming parameter **data**: everything to the right of `p` until the
26 | closing `]`. In other words, if the input to macro.do\(\) is `[p foo bar]`,
27 | then data = `foo bar`
28 | * Do something to the data. In this case, it wraps it with ``
29 | * Return the result.
30 |
31 | This is the easy one:
32 |
33 | * In aa\_macro.py, from the beginning or from `p_fn` search for `'p'`
34 |
35 | ```python
36 | 'p' : self.p_fn,
37 | ```
38 |
39 | * That's an entry in a function table. :\)
40 | * In the table put the tag string \(`'p'` in this case\) See `p_fn` entry for howto.
41 | The tag string must not contain spaces or newlines.
42 | * After the tag string, put a colon \( ':' \) See `p_fn` entry for howto.
43 | * Put the name of your function, preceded by `self.` See `p_fn` entry for howto.
44 | * Add a trailing comma
45 |
46 | Lastly, the function table is broken up into functional groups for my
47 | \(okay, and your\) convenience and no other reason. I would suggest that you
48 | put your function in the most appropriate group just for sanity's sake,
49 | but it's your barbecue, so whatever. Note that if you *don't* do so, but
50 | I accept a patch because I like your idea, I'm going to move it if I think
51 | it was poorly placed. :\)
52 |
53 | Of course, if no group really matches what you're doing, and you don't
54 | like the "misc" portion of the table, feel free to create a new section.
55 |
56 | ## A walk through the addition process
57 |
58 | Suppose we want to be able to number a list with roman numerals. First
59 | thing that might occur to you to ask is, well, uppercase roman numerals
60 | or lowercase? My answer would be, clearly, it'd be nice to have both.
61 | But two sets of code to generate them that way? Silly. So, the need for
62 | case conversion arises, and we have our first target. Which we will
63 | solve in about one minute, like this. First task, implement the actual
64 | function:
65 |
66 | ```python
67 | def upper_fn(self,tag,data):
68 | return data.upper()
69 | ```
70 |
71 | Second task, add the function and its tag to the function table:
72 |
73 | ```python
74 | 'upper' : self.upper_fn,
75 | ```
76 |
77 | Ok, that's done. But hey, while we're thinking this way, we should
78 | certainly do this; first task, implement
79 | the actual function:
80 |
81 | ```python
82 | def lower_fn(self,tag,data):
83 | return data.lower()
84 | ```
85 |
86 | Second task, add the function and its tag to the function table:
87 |
88 | ```python
89 | 'lower' : self.lower_fn,
90 | ```
91 |
92 | Now, we'll be able to do `[upper i]` and get `I` out. Or `[lower I]` and get
93 | `i` out. Spiffy. It's almost too easy, isn't it? Sure. Well, making roman numerals
94 | is a little more challenging.
95 |
96 | As numbers are handled in the usual decimal fashion within `aa_macro()`, we'll
97 | do all the work of producing, counting, etc. just as we usually would, and concentrate instead
98 | on simply converting from decimal to roman. First task, the function:
99 |
100 | ```python
101 | def roman_fn(self,tag,data):
102 | o = ''
103 | try: number = int(data)
104 | except: pass
105 | else:
106 | if number > -1 and number < 4001:
107 | romans = ['m','cm','d','cd','c','xc','l','xl','x','ix','v','iv','i']
108 | integers = [1000,900,500,400,100,90,50,40,10,9,5,4,1]
109 | for v in range(0,13):
110 | ct = int(number / integers[v])
111 | o += romans[v] * ct
112 | number -= integers[v] * ct
113 | return o
114 | ```
115 |
116 | Second task, add the function and its tag to the function table:
117 |
118 | 'roman' : roman_fn,
119 |
120 | Then we can do this:
121 |
122 | feed in: `[roman 12]`
123 | results: `xii`
124 |
125 | And we can do this...
126 |
127 | [style uroman [upper [roman [b]]]]
128 |
129 | feed in: `{uroman 4}`
130 | results: `IV`
131 |
132 | So, that's that, eh? \(Keeping in mind `macro()` can already count\)
133 |
134 | Well, no. Shouldn't be, anyway. See, that algorithm runs every time we
135 | convert a number. So it initializes those arrays every time, too. Naughty.
136 | So let's put them in the class globally, so that they only get set up once
137 | per object. This is super-simple. Just move them to the front of `macro()`,
138 | in the `__init__()` function, like so...
139 |
140 | self.romans = ['m','cm','d','cd','c','xc','l','xl','x','ix','v','iv','i']
141 | self.integers = [1000,900,500,400,100,90,50,40,10,9,5,4,1]
142 |
143 | ...and then alter `roman_fn()` accordingly:
144 |
145 | ```python
146 | def roman_fn(self,tag,data):
147 | o = ''
148 | try: number = int(data)
149 | except: pass
150 | else:
151 | if number > 0 and number < 4001:
152 | for v in range(0,13):
153 | ct = int(number / self.integers[v])
154 | o += self.romans[v] * ct
155 | number -= self.integers[v] * ct
156 | return o
157 | ```
158 |
159 | So, great, right? One more thing... roman numerals look best in a monospaced, serif font,
160 | because you need to be able to tell the difference between the letter L and the letter I.
161 | Normally, that's what the <tt></tt> tags produce in HTML, assuming they
162 | haven't been disrupted by CSS, so then we can just wrap the roman numerals in those tags.
163 | If your CSS changes <tt> such that it uses a sans-serif font, then you would use either a <font> tag or an
164 | appropriate CSS style instead (neither of which work in Github's markdown, by the way),
165 | but for this walk-through, <tt> will do:
166 |
167 | [style roman [roman [b]]]
168 | [style uroman [upper [roman [b]]]]
169 |
170 | Which allows:
171 |
172 | feed in: `{roman 15}`
173 | results: <tt>xv<tt>
174 |
175 | feed in: `{uroman 17}`
176 | results: <tt>XVII<tt>
177 |
178 | Now we're cooking.
179 |
180 | I guess now I have to go and add this to `macro()`, as it's pretty cool. But I assure you, it
181 | wasn't in the class prior to my writing this little howto. But that's the process
182 | in general, and as you can see, it's pretty open-ended. And fun.
183 |
184 | # You should understand that:
185 |
186 | Text is generally processed left to right and inside out based on bracketing.
187 | For example:
188 |
189 | [p [i foo] [b bar] [u blurgh]]
190 |
191 | Order of processing is: `i`, `b`, `u`, then `p` so internally, it goes through
192 | the following stages in exactly this order:
193 |
194 | [p [i foo] [b bar] [u blurgh]]
195 | [p foo [b bar] [u blurgh]]
196 | [p foo bar [u blurgh]]
197 | [p foo bar blurgh]
198 | foo bar blurgh
199 |
200 | Generally this won't bite you, especially in the case of a simple
201 | tag similar to `b`, but if you try to do anything tricky where one
202 | tag depends upon the result of another tag, make sure you have this
203 | processing order firmly in mind.
204 |
205 | There are some other, more complicated things in there, of course, and
206 | I'd be no less than delighted if you added things of similar complexity.
207 | In aid of this, you can ask me questions if you need to. My email address is in
208 | aa_macro.py so it's pretty easy to do. I will answer any even remotely
209 | reasonable question that isn't of the "how do I write Python" variety. I also
210 | take interesting suggestions under consideration.
211 |
212 | ## Using the unit tests
213 |
214 | Here's the basic process:
215 |
216 | 1) Add your functionality to class macro\(\)
217 | 1) Add one or more good examples to mactest.txt
218 | 1) Run test\_aa\_macro.py and observe the result\(s\)
219 | 1) if not what you wanted, recode and repeat step 4
220 | 1) Once the results are what you desire do this:
221 | `cp badoutput.html expected.html`
222 | 1) Run test\_aa\_macro.py again; now it incorporates
223 | your results. All done!
224 |
225 | ## In Closing
226 |
227 | Thanks for taking a look at my macro() class. Time is the most valuable thing
228 | we have. I truly appreciate you spending some of yours on this, and that
229 | includes casual glances.
230 |
231 | Cheers!
232 |
233 | --Ben
234 |
--------------------------------------------------------------------------------
/feature-list.md:
--------------------------------------------------------------------------------
1 | # Feature List for BETA [aa_macro.py](aa_macro.py)
2 |
3 | * Highlights
4 | * Easy to use
5 | * Fast
6 | * Powerful
7 | * Lightweight
8 | * One import
9 | * One class
10 | * One object per document
11 | * Zero non-stdlib dependencies
12 | * Zero Installation hassles
13 | * Trivially learned syntax
14 | * All use ok: commercial or otherwise. Free!
15 | * No inherent ads or other mal/anchor-ware
16 | * No reporting and no tracking
17 | * Patent-, trademark-, copyright-, and license-clean black-box design
18 |
19 | * Custom styles: `{customName options}` syntax
20 | * Capable of almost unlimited range of functionality
21 | * Examples
22 | * Counting
23 | * Alternation
24 | * Conditionality
25 | * Mathematics
26 | * Parameter parsing
27 | * Literal / Scalar discrimination (e.g. literal / $variable)
28 | * Custom escape sequences
29 | * Can replace any built-in \(see built-ins, below\)
30 | * Fully independent namespace
31 | * Utility list function \(creates data list of currently defined style\)
32 | * Can output a style verbatim in HTML without processing for reference
33 |
34 | * Built-ins: `[builtIn options]` syntax
35 | * Text styling
36 | * Bold
37 | * Italic
38 | * Underline
39 | * Quoting
40 | * To uppercase conversion
41 | * To lowercase conversion
42 | * Foreground text color
43 | * Background text color \(in HTML 4.01s mode only\)
44 | * Paragraphs
45 | * pretty-printing aa_macro source code
46 | * pretty-printing Python source code
47 | * pretty-printing c code
48 | * pretty-printing objective c code
49 | * pretty-printing c++ code
50 | * encryption and decryption, double-lock box capable
51 | * Linking
52 | * Optional verbiage
53 | * Optional stock phrasing
54 | * Images
55 | * Optional title\+alt tags
56 | * Optional encompassing link
57 | * Width and height tag handling
58 | * HTML Lists
59 | * Ordered
60 | * Unordered
61 | * Line-Item to List switching capable
62 | * Data lists
63 | * set up a list
64 | * copy lists
65 | * split lines into list
66 | * sort list
67 | * case-sensitive
68 | * case-insensitive
69 | * by integer at start of item
70 | * by ham radio callsign at start of item
71 | * append an item
72 | * change an item
73 | * length of list
74 | * list slicing
75 | * list concatination
76 | * lists as stacks (push,pop)
77 | * output a list, each item wrapped in a style
78 | * output a list item
79 | * create an 8-bit character map
80 | * translate by the character map
81 | * Data dictionaries
82 | * Create dictionary
83 | * Copy dictionaries
84 | * Retrieve dictionary keys to a list
85 | * Set dictionary value
86 | * Retrieve dictionary value
87 | * Tables
88 | * Header cells / lines
89 | * Standard cells / lines
90 | * Fully nestable
91 | * Table, row and cell level HTML option tag specification
92 | * Parsing and text manipulation
93 | * Multiple parameter splitting on any separator
94 | * Multiple parameter wrapping using any custom style
95 | * Text slicing
96 | * Preloading of specific parameter treatments
97 | * Whitespace stripping
98 | * String duplication
99 | * Find (sub)string in string
100 | * Replace (sub)string with string
101 | * Left and right justification
102 | * Centering
103 | * Length in lines, words or characters
104 | * Word-wrapping
105 | * Substring counting
106 | * Word casing - Tropic Of Consumption
107 | * Sentence casing - Tropic of consumption
108 | * Title casing - Tropic of Consumption
109 | * Special casing - html to HTML, internet to Internet, etc.
110 | * Word/keyword expansion/replacement
111 | * Multi-element replacement
112 | * Soundex coding
113 | * HTML tag stripping
114 | * String interspersion
115 | * sort lines:
116 | * case-sensitive
117 | * case-insensitive
118 | * by integer at start of line
119 | * by ham radio callsign at start of line
120 | * Variables
121 | * Locals suitable for by-page processing
122 | * Globals suitable for by-document processing
123 | * Fully clearable within object
124 | * General Stack
125 | * Push on
126 | * Push N deep
127 | * Pop
128 | * Fetch with offset
129 | * Flush
130 | * Math and number processing
131 | * Add
132 | * Subtract
133 | * Multiply
134 | * Divide
135 | * Max
136 | * Min
137 | * Increment
138 | * Decrement
139 | * Integer comma separation \(e.g. 1234 = 1,234\)
140 | * Float comma separation \(e.g. 1234.56 = 1,234.56\)
141 | * Decimal to Roman numeral conversion \(e.g. 17 = "xvii"\)
142 | * Decimal to character conversion \(e.g. 49 = "A"\)
143 | * Decimal to base 16, 8 and 2 conversion, optional length control
144 | * Base 16, 8 and 2 conversion to decimal, optional length control
145 | * stage values between ranges to any number of steps
146 | * Conditionals
147 | * On parameter match
148 | * On parameter non-match
149 | * On parameter present
150 | * On parameter non-present
151 | * On parameter odd
152 | * On parameter even
153 | * On Parameter less than or equal
154 | * On Parameter greater than or equal
155 | * Miscellaneous
156 | * switch, case, for and in operators
157 | * "Include" files
158 | * Embrace, extend or supercede any built-in function
159 | * Comments \(do not appear in output\)
160 | * Escapes for all processor encodings
161 | * HTML 3.2 and 4.01s modes
162 | * time and date
163 | * execute shell command and incorporate output
164 | * forward-reference resolution
165 |
166 | * Utilities
167 | * Built-in example suite
168 | * Comprehensive unit test
169 | * Markdown conversion
170 | * Parameter sanitation
171 | * Local dump \(text, html, table dump options\)
172 | * Global dump \(text, html, table dump options\)
173 | * Style dump \(text, html, table dump options\)
174 |
175 | * Of Special Note
176 | * Independent of both LORAN and the GPS constellation
177 | * No ultraviolet radiation emissions whatsoever
178 | * Fully Functional at any depth or altitude
179 | * Created exclusively using NY-Style Pizza
180 | * Never requires lubrication before use
181 | * Packed with Wholesome Goodness
182 | * Will not attract mosquitos
183 | * Diet neutral: 0 calories
184 | * Gluten-free
185 | * Unisex
186 | * Pet safe
187 | * Hypoallergenic
188 | * Zero landfill impact
189 | * Indescribably Delicious
190 | * Will not fray or stain lingerie
191 | * 100% pro-feline production environment\*
192 | * Contains no GMOs, vaccines, or fluoridation
193 | * Rainbow-friendly: Spectrum-In == Spectrum Out
194 | * Fully Organic Production Methods used throughout
195 | * Transport on aircraft will not result in chemtrails
196 |
197 | \* Endorsed by Leo
198 |
199 | 
200 |
201 |
--------------------------------------------------------------------------------
/files.md:
--------------------------------------------------------------------------------
1 | # [aa_macro.py](aa_macro.py) Project Files
2 |
3 | File | Project Component
4 | ---- | -----------------
5 | [aa_ansiicolor.py](aa_ansiicolor.py) | Python import library used by unit tests
6 | [aa_macro.py](aa_macro.py) | Python import library implementing project functionality
7 | [aagen](aagen) | command line utility to filter / process input macro() src
8 | [aagen-example.txt](aagen-example.txt) | Example source file for [aagen](aagen)
9 | [authoring.md](authoring.md) | Tips on how to author for [aa_macro.py](aa_macro.py)
10 | [changelog.md](changelog.md) | Change log
11 | [enhancement.md](enhancement.md) | Guide to adding functionality to [aa_macro.py](aa_macro.py)
12 | [expected.html](expected.html) | Used by unit tests
13 | [feature-list.md](feature-list.md) | Project feature list
14 | **files.md** | This File
15 | [leo.png](leo.png) | Photo of endorsing party
16 | [mactest.txt](mactest.txt) | Used by unit tests
17 | [martomac.README.md](martomac.README.md) | General explanation of [martomac.py](martomac.py)
18 | [martomac.py](martomac.py) | Markdown-to-aa\_macro() format convertor
19 | [mtm.md](mtm.md) | Test file for [martomac.py](martomac.py)
20 | [mycustommd.mac](mycustommd.mac) | Sample file for [martomac.py](martomac.py) \-m option
21 | [qr_html.txt](qr_html.txt) | style file to generate HTML from quickref.txt
22 | [qr_markdown.html](qr_markdown.html) | style file to generate markdown from quickref.txt
23 | [quickref.txt](quickref.txt) | Quick reference source in macro\(\) format
24 | [quickref.html](quickref.html) | Quick reference in HTML
25 | [README.md](README.md) | General explanation of project intent, fit
26 | [tease.png](tease.pg) | Image used in [README.md](README.md)
27 | [test.gif](test.gif) | Test image for unit tests
28 | [test.jpg](test.jpg) | Test image for unit tests
29 | [test.png](test.png) | Test image for unit tests
30 | [test_aa_macro.py](test_aa_macro.py) | Unit tests
31 | [testing.README.md](testing.README.md) | General explanation of unit tests
32 | [textmate-syntax.txt](textmate-syntax.txt) | OS X Textmate syntax highlighting for macro\(\)
33 | [todo.md](todo.md) | List of remaining project goals
34 | [unknown.syntax](unknown.syntax) | Midnight Commander syntax highlighting for macro\(\)
35 | [users-guide.md](users-guide.md) | How to use class `macro()` to process text
36 |
--------------------------------------------------------------------------------
/forvariable.txt:
--------------------------------------------------------------------------------
1 | This content came from a text file.
2 |
--------------------------------------------------------------------------------
/genquickref.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | ./aagen -i qr_html.txt -f quickref.html quickref.txt -r
4 | ./aagen -i qr_markdown.txt -f quickref.md quickref.txt -r
5 |
--------------------------------------------------------------------------------
/leo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fyngyrz/aa_macro/34f09ebbefd1c02fd31366dd17de2f7c0f6f877f/leo.png
--------------------------------------------------------------------------------
/mactest.txt:
--------------------------------------------------------------------------------
1 | [style h1 [b]
]
2 | [style h2 [b]
]
3 | [style h3 [b]
]
4 | [style test [b]]
5 | [style code [b]
]
6 | [style hello Why hello, [b], how are you?]
7 | [style blue [b]]
8 | [style mopt {blue [b [lb][b][rb]]}]
9 |
10 | [style qrs
11 | [table border="1" bgcolor="#ffffdd",
12 | [row ,[cell align="center",Quick Reference to Scripting Command]]
13 | [row ,[cell bgcolor="#dddddd", [b]]]
14 | [row ,
15 | [cell bgcolor="#ddffdd",[i Items in] [b CAPS] [i are] [b 0/1] [i switches or switches with more options than] [b 0/1][i .]
16 | [i Multiple options are indicated by a range in brackets, such as] mopt 0-2[i .]
17 | ]]]]
18 |
19 | {hello moe}
20 | {hello
21 | larry}
22 | {hello curly}
23 |
24 | [load myvar forvariable.txt]
25 | [lv myvar]
26 | [gload othervar forvariable.txt]
27 | [gv othervar]
28 |
29 | [raw test 123]
30 | [graw trust 456]
31 | [v trust]
32 | [v test]
33 |
34 | {h1 Test Results: aa_macro.py}
35 |
36 | {h2 Text Formatting}
37 | [mode 4.01s]
38 |
39 | [back 028]
40 | {h3 HTML 4.01s Mode:}
41 | [p [b bold text]]
42 | [p [i italic text]]
43 | [p [u underlined text]]
44 | [p [color 876 color3]]
45 | [p [color fedcba color6]]
46 | [mode 3.2]
47 | {h3 HTML 3.2 Mode:}
48 | [p [u [i [b {hello Ben}]]]]
49 | [p [color 876 color3]]
50 | [p [color fedcba color6]]
51 |
52 | {h2 linking}
53 | [p [a http://fyngyrz.com]]
54 | [p [a tab,http://fyngyrz.com]]
55 | [p [a tab,http://fyngyrz.com,My Link]]
56 | [p [a http://fyngyrz.com,My Other Link]]
57 | [p [web http://fyngyrz.com]]
58 | [p [web http://fyngyrz.com Another Link]]
59 | [p [link http://fyngyrz.com]]
60 | [p [link http://fyngyrz.com Another Link]]
61 | [urlencode hi, Fred & linda]
62 |
63 | {h2 Images}
64 | {h3 No size, no local lookup so no relative path}
65 | [p [img http://fyngyrz.com/images/beachflag.png http://fyngyrz.com]]
66 | [p [img http://fyngyrz.com/images/beachflag.png]]
67 | [p [img Beach Flag,http://fyngyrz.com/images/beachflag.png]]
68 | [p [img Beach Flag,http://fyngyrz.com/images/beachflag.png http://fyngyrz.com]]
69 |
70 | {h3 Size, identical (empty) relative path}
71 | [p [locimg test.png http://fyngyrz.com]]
72 | [p [locimg test.png]]
73 | [p [locimg .png Test,test.png]]
74 | [p [locimg .png Test,test.png http://fyngyrz.com]]
75 | [p [locimg lpath=/usr/web/,wpath=/mypics/,test.png]]
76 |
77 | [p [locimg test.jpg http://fyngyrz.com]]
78 | [p [locimg test.jpg]]
79 | [p [locimg .jpg Test,test.jpg]]
80 | [p [locimg .jpg Test,test.jpg http://fyngyrz.com]]
81 |
82 | [p [locimg test.gif http://fyngyrz.com]]
83 | [p [locimg test.gif]]
84 | [p [locimg .gif Test,test.gif]]
85 | [p [locimg .gif Test,test.gif http://fyngyrz.com]]
86 |
87 | {h3 Size, relative path only}
88 | [lipath ./]
89 | [p [locimg test.png http://fyngyrz.com]]
90 | [p [locimg test.png]]
91 | [p [locimg .png Test,test.png]]
92 | [p [locimg .png Test,test.png http://fyngyrz.com]]
93 |
94 | [p [locimg test.jpg http://fyngyrz.com]]
95 | [p [locimg test.jpg]]
96 | [p [locimg .jpg Test,test.jpg]]
97 | [p [locimg .jpg Test,test.jpg http://fyngyrz.com]]
98 |
99 | [p [locimg test.gif http://fyngyrz.com]]
100 | [p [locimg test.gif]]
101 | [p [locimg .gif Test,test.gif]]
102 | [p [locimg .gif Test,test.gif http://fyngyrz.com]]
103 |
104 | {h3 Size, relative path and http path}
105 | [lipath ./]
106 | [p [locimg randomdir/test.png http://fyngyrz.com]]
107 | [p [locimg randomdir/test.png]]
108 | [p [locimg .png Test,randomdir/test.png]]
109 | [p [locimg .png Test,randomdir/test.png http://fyngyrz.com]]
110 |
111 | [p [locimg randomdir/test.jpg http://fyngyrz.com]]
112 | [p [locimg randomdir/test.jpg]]
113 | [p [locimg .jpg Test,randomdir/test.jpg]]
114 | [p [locimg .jpg Test,randomdir/test.jpg http://fyngyrz.com]]
115 |
116 | [p [locimg randomdir/test.gif http://fyngyrz.com]]
117 | [p [locimg randomdir/test.gif]]
118 | [p [locimg .gif Test,randomdir/test.gif]]
119 | [p [locimg .gif Test,randomdir/test.gif http://fyngyrz.com]]
120 |
121 | [limg test.png]
122 | [limg title=a pic,test.png]
123 | [limg alt=testpng,test.png]
124 | [limg target=http://ourtimelines.com,test.png]
125 | [locimg lpath=/usr/web/,wpath=/mypics/,test.png]
126 |
127 | {h2 Multiple Style Invocation}
128 | [style a a[b]a]
129 | [style b b[b]b]
130 | [locs a X]
131 | [locs b X]
132 | [locs a,b X,Y]
133 |
134 | [gstyle c c[b]c]
135 | [gstyle d d[b]d]
136 | [glos c X]
137 | [glos d X]
138 | [glos c,d X,Y]
139 |
140 | [s a X]
141 | [s b X]
142 | [s c X]
143 | [s d X]
144 | [s a,b,c,d W,X,Y,X]
145 | {a,b,c,d J,K,L,M}
146 |
147 | [s sep=|,a,b,c,d N|O|P|Q]
148 | [locs sep=|,a,b A|S]
149 | [glos sep=|,c,d B|T]
150 | {sep=|,a,b,c,d A|S|I|A}
151 |
152 | {h2 HTML Lists}
153 | [style lwrap [b]]
154 | [p [ul item1,item2]]
155 | [p [ul sep=|,item1|item2|item3]]
156 | [p [ul wrap=lwrap,item1,item2]]
157 | [p [ul wrap=lwrap,sep=|,itemW|itemX]]
158 | [p [ul sep=|,wrap=lwrap,itemY|itemZ]]
159 | [p [ol item1,item2]]
160 | [p [iful item1]]
161 | [p [iful item1,item2]]
162 | [p [ifol item1]]
163 | [p [ifol item1,item2]]
164 | [p [t a,b,c]]
165 | [p [t wrap=code,a,b,c]]
166 | [p [t wrap=code,sep=|,d|e|f]]
167 |
168 | [ul istyle=color:#ff0000,a,b,c]
169 | [ul lstyle=font-weight: bold;,a,b,c]
170 | [ul lstyle=margin-bottom: .5em;,istyle=color:#00ff00,a,b,c]
171 |
172 | [iful istyle=color:#ff0000,item1]
173 | [iful istyle=color:#ff0000,item1,item2]
174 | [ifol istyle=color:#ff0000,item1]
175 | [ifol istyle=color:#ff0000,item1,item2]
176 |
177 | [iful lstyle=font-weight: bold;,item1]
178 | [iful lstyle=font-weight: bold;,item1,item2]
179 | [ifol lstyle=font-weight: bold;,item1]
180 | [ifol lstyle=font-weight: bold;,item1,item2]
181 |
182 | [iful lstyle=margin-bottom: .5em;,istyle=color:#00ff00,item1]
183 | [iful lstyle=margin-bottom: .5em;,istyle=color:#00ff00,item1,item2]
184 | [ifol lstyle=margin-bottom: .5em;,istyle=color:#00ff00,item1]
185 | [ifol lstyle=margin-bottom: .5em;,istyle=color:#00ff00,item1,item2]
186 |
187 | {h2 Tables}
188 | [table
189 | [row [header col 1][header col 2]]
190 | [row [cell test1][cell test2]]
191 | ]
192 | [table border=0,
193 | [row [header bgcolor="#ffffff",col 1][header col 2]]
194 | [row bgcolor="#888888",[cell test1][cell align="center", test2]]
195 | ]
196 |
197 | {h2 Variables}
198 | [p
199 | [local foo bar][v foo]
200 | [global bing bong][v bing]
201 | [global foo bip][v foo][gv foo][lv foo]
202 | [page][v foo][gv foo][lv foo] Hooray!
203 | [local x 1]
204 | [vinc x]
205 | [vdec x]
206 | [vinc pre=1,x]
207 | [vdec pre=1,x]
208 | [v x]
209 | ]
210 |
211 | {h2 stack}
212 | [p
213 | [push X]stack="[pop ]"
214 | [push X][push Y][push Z]stack="[pop ]","[pop ]",[pop ]"
215 | [push 3,bugger]stack="[pop ]","[pop ]","[pop ]"
216 | [push X][push Y][push Z][flush]stack="[pop ]","[pop ]","[pop ]"
217 | [push X][push Y][push Z]stack 1="[fetch 1]"[flush]
218 | [push sep=|,5|five]"[pop ]","[pop ]","[pop ]","[pop ]","[pop ]"
219 | ]
220 |
221 | {h2 Math}
222 | [p
223 | [int 34.5]
224 | [int 02]
225 | [abs -3]
226 | [abs 3.2]
227 | [abs -6.7]
228 | [add -1 6]
229 | [sub 10 9]
230 | [mul 3 5]
231 | [div 72 9]
232 | [inc 1]
233 | [dec 10]
234 | max 5 10 = [max 5 10]
235 | max 9 4 = [max 9 4]
236 | min 5 10 = [min 5 10]
237 | min 4 9 = [min 4 9]
238 | stage 100 50 10 5 = [stage 100 50 10 5]
239 | stage 50 75 10 5 = [stage 50 75 10 5]
240 | stage mode=float,digits=1,0 1 10 5 = [stage mode=float,digits=1,0 1 10 5]
241 | stage mode=float,digits=3,0 1 10 10 = [stage mode=float,digits=3,0 1 10 10]
242 | stage mode=float,0 1.5 3 2 = [stage mode=float,0 1.5 3 2]
243 | stage mode=float,2.5 3.5 2 1 = [stage mode=float,2.5 3.5 2 1]
244 | stage mode=float,digits=6,0 10 3 1 = [stage mode=float,digits=6,0 10 3 1]
245 | stage mode=float,.5 .75 5 2 = [stage mode=float,.5 .75 5 2]
246 | stage mode=float,0 1 10 5.5 = [stage mode=float,0 1 10 5.5]
247 | ]
248 |
249 | {h2 Conditionals}
250 | [style mmmm --[b]--]
251 | [p
252 | [even 2 EVEN][even 1 !ODD!]
253 | [odd 1 ODD][odd 2 !EVEN!]
254 | [if bleep bleep Match][if foo bar !NO MATCH!]
255 | [if sep=|,bleep|bleep|sepMatch][if sep=|,foo|bar|!NO sepMATCH!]
256 | [if sep=[co],bleep,bleep,comMatch][if sep=[co],foo,bar,!NO comMATCH!]
257 | [else sep=|,foo|bar|No sepMatch][else sep=|,bleep|bleep|!sepMATCH!]
258 | [else sep=[co],foo,bar,No comMatch][else sep=[co],bleep,bleep,!comMATCH!]
259 | [else foo bar No Match][else bleep bleep !MATCH!]
260 | 1: [if style=mmmm,bleep bleep Match][if style=mmmm,foo bar NO MATCH]
261 | 2: [else style=mmmm,foo bar No Match][else style=mmmm,bleep bleep MATCH]
262 | 1 [ne something,Something][ne ,!EMPTY!]
263 | 2 [ne sep=|,something|Something][ne sep=|,|!EMPTY!]
264 | 3 [ne ,Something][ne something,!EMPTY!]
265 | 4 [ne sep=|,|Something][ne sep=|,something|!EMPTY!]
266 | 5 [eq something,Something][eq ,!EMPTY!]
267 | 6 [eq sep=|,something|Something][eq sep=|,|!EMPTY!]
268 | 7 [eq ,Something][eq something,!EMPTY!]
269 | 8 [eq sep=|,|Something][eq sep=|,something|!EMPTY!]
270 | [local fooge blah]
271 | [local pooge]
272 | [ne [v fooge],Something][ne [v pooge],!EMPTY!]
273 | [eq [v fooge],Something][eq [v pooge],!EMPTY!]
274 | ]
275 |
276 | {h2 Parsing and text processing}
277 | [style sdex [b] Soundex: [soundex [b]]]
278 | [p
279 | [slice 3:9,catmonkeydog]test2
280 | [split |,foo|bar|bleep|blop]test3
281 | [parm 0] [parm 1] [parm 2] [parm 3]test 4
282 | [upper i was lower, but now am high]
283 | [lower I WAS HIGHER, BUT NOW AM BROUGHT LOW]
284 | I have a [upper [roman 427]] Hemi ox-cart
285 | [chr 66][chr 69][chr 78]
286 | [csep 1234567890]
287 | [fcsep 12345678.90]
288 | 17 dec to hex: [dtohex 17]
289 | 9 dec to oct: [dtooct 9]
290 | 3 dec to bin: [dtobin 3]
291 | 11 hex to dec: [htodec 11]
292 | 11 oct to dec: [otodec 11]
293 | 11 bin to dec: [btodec 11]
294 | 97 hex to binary: [dtobin [htodec 97]]
295 | 11010110 to hex: [upper [dtohex [btodec 11010110]]]
296 |
297 | 7 dec to hex 2-digits: [dtohex digits=2,7]
298 | 7 dec to oct 3-digits: [dtooct digits=3,7]
299 | 9 dec to bin 8-digits: [dtobin digits=8,9]
300 | 11 hex to dec 3-digits: [htodec digits=3,11]
301 | 11 oct to dec 3-digits: [otodec digits=3,11]
302 | 11 bin to dec 3-digits: [btodec digits=3,11]
303 |
304 | [style setme tothis]
305 | should be "tothis": "{setme}"
306 | [style setme]
307 | should be no content: "{setme}"
308 | [gstyle gsetme tothat]
309 | should be "tothat": "{gsetme}"
310 | [gstyle gsetme]
311 | should be no content: "{gsetme}"
312 | stripe charset=xy,xytestingyx = [stripe charset=xy,xytestingyx]
313 |
314 | [hmap hlist]
315 | [translate hlist,ABC]
316 | [translate pre=0x,inter=[co] ,post=.,hlist,ABC]
317 |
318 | [local cont this is a test
319 | of the emergency broadcast system]
320 | content:
321 | [v cont]
322 | lines: [lc [v cont]]
323 | words: [wc [v cont]]
324 | chars: [len [v cont]]
325 | [lc]
326 | [wc]
327 | [len]
328 | [b style [color f84 me]]
329 | [i]
330 | [u]
331 | [local cont thaAAAaaas right all]
332 | content: [v cont]
333 | a: [count a,[v cont]]
334 | aa: [count aa,[v cont]]
335 | overlaps=yes,aa: [count overlaps=yes,aa,[v cont]]
336 | sep=|,overlaps=yes,aa: [count sep=|,overlaps=yes,aa|[v cont]]
337 | casesens=yes,aa: [count casesens=yes,aa,[v cont]]
338 | casesens=yes,AA: [count casesens=yes,AA,[v cont]]
339 | overlaps=yes,casesens=yes,AA: [count overlaps=yes,casesens=yes,AA,[v cont]]
340 | sep=|,overlaps=yes,casesens=yes,AA: [count sep=|,overlaps=yes,casesens=yes,AA|[v cont]]
341 | {sdex Knuth}
342 | {sdex Asimov}
343 | {sdex Clarke}
344 | {sdex Einstein}
345 | [local cont [color 567 testing [b 1 [i 2] 3]]]
346 | content: [v cont]
347 | stripped of tags: [strip [v cont]]
348 | Hamcalls:
349 | [hsort W3OZ Larry
350 | N2MGA
351 | AA7AS,Ben
352 | w2jvm Harold
353 | W2GGI Robert
354 | N5CST!Johann!
355 | KE4TP-Pete]
356 | ]
357 |
358 | {h2 aa_macro and Python Parsing}
359 | [postparse
360 | from aa_macro import *
361 |
362 | mod = macro()
363 |
364 | inputtext = '[lb]i print \'some\' "content" from here[rb][lb]local foo bar[rb]'
365 | outputext = mod.do(inputtext)
366 | print outputtext
367 |
368 | inputtext = "[lb]b \"more\" 'content'[rb] [lb]v foo[rb]" # as we're using the same object, anything...
369 | outputext = mod.do(inputtext) # ...set up in it is still in context here
370 | print outputtext
371 | ]
372 |
373 | [pythparse
374 | from aa_macro import *
375 |
376 | mod = macro()
377 |
378 | inputtext = '[i print \'some\' "content" from here][local foo bar]'
379 | outputext = mod.do(inputtext)
380 | print outputtext
381 |
382 | inputtext = "[b \"more\" 'content'] [v foo]" # as we're using the same object, anything...
383 | outputext = mod.do(inputtext) # ...set up in it is still in context here
384 | print outputtext
385 | ]
386 |
387 | [v loc_pyth]
388 |
389 | [local txl_lf
[lf]]
390 | [gstyle key [b]]
391 | [gstyle keyhints
392 |
400 | [i Keyboard Navigation]
401 |
402 | {key ,} Previous Page
403 | {key .} Next Page
404 | {key t} TOC
405 | {key i} Index
406 | ]
407 |
408 | [slit keyhints]
409 | [v loc_slit]
410 |
411 | {h2 switch/case}
412 | switch (csep=X,)(isep=Y,)(default=styleName,)switchName caseXstyleName(YcaseXstylename)
413 | [style foo foo([b])bar]
414 | [style bar bar([b])foo]
415 | [switch test1 1|foo,2|bar]
416 | [case test1 1,bah]
417 | [case sep=|,test1 2|humbug]
418 | [style rude dude:[b]!]
419 | [style remark remark:"[b]"]
420 | [style huh ??[b]??]
421 | [switch csep=^,isep=$,test2 A$rude^B$remark]
422 | [case test2 A,shhhh]
423 | [case test2 B,speaking extemporaneously]
424 | [switch default=huh,test3 x|foo,y|bar]
425 | [case test3 x,with-foo]
426 | [case test3 y,with-bar]
427 | [case test3 z,with-nothing]
428 |
429 | {h2 for/in}
430 | [style mmm [b] ]
431 | [for mmm,0,10,2]
432 | [list listx,a,c,d,c]
433 | [in mmm,listx]
434 |
435 | {h2 Data Lists}
436 | [list slicetest,a,2,c,4,e,6,g,8]
437 | slicetest list: [dlist slicetest]
438 | 1 = [lslice 1,slicetest,sliceresult]
439 | [dlist sliceresult]
440 | 2:3 = [lslice 2:3,slicetest,sliceresult]
441 | [dlist sliceresult]
442 | :4 = [lslice :4,slicetest,sliceresult]
443 | [dlist sliceresult]
444 | 4: = [lslice 4:,slicetest,sliceresult]
445 | [dlist sliceresult]
446 | ::-1 = [lslice ::-1,slicetest,sliceresult]
447 | [dlist sliceresult]
448 | [list stacker,e,f,g,h,i]
449 | [dlist stacker]
450 | [lpush stacker,k]
451 | [dlist stacker]
452 | [lpop stacker]
453 | [lpop stacker]
454 | [lpop stacker,-2]
455 | [dlist stacker]
456 | [list lowers,a,b,c]
457 | list length of a,b,c: [llen lowers]
458 | [e lowers,2] [e lowers,1] [e lowers,0]
459 | [list sep=|,uppers,A|B|C]
460 | [append uppers,amphetamine]
461 | [lset uppers,1,aircraft]
462 | [e uppers,2] [e uppers,1] [e uppers,0] [e uppers,3]
463 | [dlist uppers]
464 | [style quotes "[b]" ]
465 | [dlist style=quotes,uppers]
466 | [cmap xlate]
467 | [e xlate,66]
468 | [translate xlate,ALPHA]
469 | [lset xlate,65,-a-]
470 | [translate xlate,ALPHA]
471 | [list unsorted,larry,ben,Beth,alan,leroy]
472 | [dlist style=quotes,unsorted]
473 | [asort unsorted]
474 | [dlist style=quotes,unsorted]
475 | [aisort unsorted]
476 | [dlist style=quotes,unsorted]
477 | [list sep=|,nunsorted,44,larry|1,ben|2,Beth|3,alan,smith|5,leroy]
478 | [dlist style=quotes,nunsorted]
479 | [isort nunsorted]
480 | [dlist style=quotes,nunsorted]
481 | [style nonquotes [splitcount 1][split [co],[b]]"[parm 1]" ]
482 | [dlist style=nonquotes,nunsorted]
483 | [ltol nlist,line 1
484 | line 2
485 | line3]
486 | [dlist nlist]
487 | [list hamlist,W3OZ Larry,N2MGA,AA7AS Ben,w2jvm Harold,W2GGI Robert,N5CST!Johann!,KE4TP-Pete]
488 | [style hwrap [b][nl]]
489 | [local cbar 123456789 ]
490 | [local cont this is line one
491 | this is line two
492 | this is line three
493 | this is line four and I'm really not kidding about this at all, no fooling, folks
494 | and this is the last line]
495 |
496 | Word wrap at 72 columns
497 | [dup 8,[v cbar]]
498 | [wwrap 72,[v cont]]
499 |
500 | Word wrap at 31 columns
501 | [dup 4,[v cbar]]
502 | [wwrap 31,[v cont]]
503 |
504 | Word wrap at 72 columns, with style
505 | [style mywrap ([b])[nl]]
506 | [dup 8,[v cbar]]
507 | [wwrap wrap=mywrap,72,[v cont]]
508 |
509 | Word wrap at 31 columns, with style
510 | [style mywrap ([b])[nl]]
511 | [dup 4,[v cbar]]
512 | [wwrap wrap=mywrap,31,[v cont]]
513 |
514 | Word wrap with HTML
515 | 123456789 123456789 123456789
516 | [wwrap 30,This is a test of the emergency broadcast system. This is only a test. If this had been a real emergency, you
517 | would have been instructed to weep in abject fear.]
518 |
519 | Word wrap with HTML, but not counting it
520 | 123456789 123456789 123456789
521 | [wwrap nohtml=1,30,This is a test of the emergency broadcast system. This is only a test. If this had been a real emergency, you
522 | would have been instructed to weep in abject fear.]
523 |
524 | Unsorted list:
525 | --------------
526 | [dlist style=hwrap,hamlist]
527 |
528 | Sorted List:
529 | ------------
530 | [lhsort hamlist]
531 | [dlist style=hwrap,hamlist]
532 |
533 | first, middle and last styles
534 | -----------------------------
535 | [style first -[b] ]
536 | [style middle :[b]: ]
537 | [style last [b]-]
538 | [list list1,a,b,c,d]
539 | [dlist fs=first,style=middle,ls=last,list1]
540 |
541 | With nice interspersion:
542 | ------------------------
543 | [list sep=|,myList,aa7as (Ben)|N5CST (Johann)|W3Oz (Larry)]
544 | [lhsort myList]
545 | [style hwrap [ne [v call],, ][b][local call [b]]]
546 | [local call]
547 | [dlist style=hwrap,myList]
548 |
549 | {h2 Data Dictionaries}
550 | [dict mydict,foo:bar,gee:whiz]'
551 | gee="[d mydict,gee]"
552 | foo="[d mydict,foo]"
553 | bip="[d mydict,bip]"
554 | resetting foo...\n[setd mydict,foo:guggle]'
555 | foo="[d mydict,foo]"
556 |
557 | {h2 Text Processing}
558 | [dup 3,foo]
559 | [eval 5,bar]
560 | [local x 0]
561 | [style bing [vinc x]:[b] ]
562 | [stripe [eval style=bing,5,blarg]]
563 | [rstrip testing 3 ]
564 | [find ani,pusilanimous]
565 | [find sep=|,we|and,then we said "no"]
566 | [replace foo,bar,you foo this]
567 | [replace sep=|,jim|larry|mark, jim, or leroy]
568 | [rjust 6,-,four]
569 | [rjust 6, ,three]
570 | [rjust 6, ,foo]
571 | '[center 7,-,bar]' odd in odd, left side pad only
572 | '[center -7,-,xyz]' odd in odd, pad both sides
573 | '[center -7,-,wxyz]' even in odd, pad both sides
574 | '[center -8,-,xyz]' odd in even, pad both sides
575 | [capt joe and the dog]
576 | [capt the exception]
577 | [capt tropic OF consumption]
578 | [capt joe and a dog]
579 | [capw joe and a dog]
580 | [caps joe and a dog]
581 | [list cvt,HTML,Python,PHP]
582 | [scase cvt,I prefer html, and python, to Html and php.]
583 | [inter -,L,4,1234567890]
584 | [inter -,R,4,1234567890]
585 | [ssort fred
586 | zander
587 | larry
588 | Marge
589 | ben]
590 | [sisort fred
591 | zander
592 | larry
593 | Marge
594 | ben]
595 | [issort 5,fred
596 | 4,zander
597 | 2,larry
598 | 3,Marge
599 | 1,ben]
600 |
601 | {h2 Escapes}
602 | [co]
603 | [vb]
604 | [lt][sp][gt][nl]
605 | [lb][sp][rb][lf]
606 | [ls][sp][rs][nl]
607 |
608 | {h2 Miscellanea}
609 | [p
610 | [local v1 3]
611 | [global v1 5]
612 | [split [co],7,2,4]
613 | [repeat 2 two ]test1[comment Invisible Me]
614 | [repeat [v v1] three ]
615 | [repeat [lv v1] three again: ]
616 | [repeat [gv v1] five ]
617 | [repeat [parm 1] two ]
618 | ]
619 | [gstyle h3 Third-level title [b]]
620 | [p
621 | [ghost h3]
622 | [ghost source=global,h3]
623 | [ghost source=local,h3]
624 | {h3 humma humma}
625 | ]
626 | [dict mydict,messed:foo,up:bar,gee:darn,whiz:it,really:truly]
627 | [local content Gee whiz, this is //really// messed up!]
628 | [v content]: [expand mydict,[v content]]
629 | [dict tonedown,befunked:bewildered,clueless:confused,afraid:nervous]
630 | [local content Befunked, afraid -- and *clueless*.]
631 | [v content] = [expand tonedown,[v content]]
632 | [dict dbldown,silly:a flaming-idiot]
633 | [expand dbldown,This person is silly!]
634 | [p
635 | [include aagen-example.txt]
636 | [embrace embrace-example.py]
637 | happy extension: [happy this is a good thing]
638 | unhappy extension: [unhappy this is a bad thing]
639 | back-reference to parent by embraced module: [dtcase]
640 | Replacement of [lb]i[rb]: [i emphasize me]
641 | [list li1,a,b,c]
642 | [list li2,d,e,f]
643 | [lcc li1,li2,li3]
644 | [dlist li3]
645 | [lcopy li3,li4]
646 | [dlist li4]
647 | [list makeEnts,&|&,"|"]
648 | [lsub makeEnts,"She & me & some Tequila"]
649 | ]
650 | if 5 <= 4 lte = [ifle 5,4,lte]
651 | if 5 <= 5 lte = [ifle 5,5,lte]
652 | if 5 <= 6 lte = [ifle 5,6,lte]
653 | if 5 >= 4 gte = [ifge 5,4,gte]
654 | if 5 >= 5 gte = [ifge 5,5,gte]
655 | if 5 >= 6 gte = [ifge 5,6,gte]
656 | [sys echo shell test]
657 | -----
658 | [fref thing] and again: [fref thing]
659 | -----
660 | [resolve thing,foobar, brother]
661 | -----
662 | [fref co] and again: [fref co]
663 | -----
664 | [resolve hex=1,co,2c]
665 | -----
666 | [th 1] [th 2] [th 3] [th 4]
667 | [nd 1] [nd 2] [nd 3] [nd 4]
668 | [style showab [split [co],[b]][parm 0][parm 1]]
669 | {showab C,D,E}
670 | [dict hcdict,Marty:KA7GKN,Ben:AA7AS,Larry:W3OZ,George:W4KVU]
671 | [dcopy hcdict,yourdict]
672 | [dkeys yourdict,keylist]
673 | [dlist keylist]
674 | [style keyvalue [splitcount 2][split |,[b]][parm 1]: [d [parm 0],[parm 1]][parm 2]]
675 | [asort keylist]
676 | [dlist style=keyvalue,parms=hcdict|,posts=|[nl],keylist]
677 | [style foo barbeque]
678 | [ifge style=foo,4,5, hello[nl]]
679 | [ifge style=foo,5,4, dolly[nl]]
680 |
681 | [getc plugin_demo.c]
682 | [getc high=c,plugin_demo.c]
683 |
684 | [ol sep=|,start=7,seven|eight|nine]
685 | [ol sep=|,type=A,seven|eight|nine]
686 | [ol sep=|,type=A,start=3,seven|eight|nine]
687 |
688 | {mopt a-b}
689 |
690 | [alphalead abcd1234 test]
691 | [alphanumlead abcd1234 test]
692 |
693 | [alphalead trail=1,abcd1234 test]
694 | [alphanumlead trail=1,abcd1234 test]
695 |
696 | [url http://fyngyrz.com/|Home]
697 | [url nam=glop,]
698 | [url nam=foo]
699 | [url tgt=_blank,http://fyngyrz.com/|Home Page]
700 | [url css=text-decoration: underline;,http://fyngyrz.com/|Home Page]
701 | [url sep=[co],http://fyngyrz.com/,Home Page]
702 |
703 | [raw c void main()
704 | {
705 | printf("Hello, Whirled\n");
706 | }]
707 | [getc var=c]
708 |
709 | [local test1 this is a test]
710 | [save test1 aam_test1.txt]
711 | [global test2 this is also a test]
712 | [gsave test2 aam_test2.txt]
713 |
714 | [local x [encrypt breakat=8,seed=19,icount=5,salt=fibble de gook,this is a test]]
715 | [v x]
716 | [decrypt seed=19,icount=5,salt=fibble de gook,[v x]]
717 |
718 | [encrypt this is also a test]
719 | [decrypt [encrypt this is also a test]]
720 |
721 | [style ripple *[b]* ]
722 | [splash style=ripple,1,2,3,4]
723 | [splash style=ripple,sep=|,a|b|c|d]
724 | [splash style=ripple,sep=/,limit=2,i/ii/iii/iv]
725 |
726 | [splash inter=-,1,2,3,4]
727 | [splash inter=[co] ,ntl= and ,1,2,3,4]
728 | [splash pre=x,post=y,inter= ,1,2,3,4]
729 | [splash ntl= and ,pre=x,post=y,inter= ,1,2,3,4]
730 |
731 | [style rapple ([b])]
732 | [style wrinkle [v loc_splashnum]:[b][nl]]
733 | [splash style=rapple,inter=-,1,2,3,4]
734 | [splash style=rapple,inter=[co] ,ntl= and ,1,2,3,4]
735 | [splash style=rapple,pre=x,post=y,inter= ,1,2,3,4]
736 | [splash style=rapple,ntl= and ,pre=x,post=y,inter= ,1,2,3,4]
737 | [splash style=wrinkle,grape,cherry,persimmon]
738 |
739 | [br]
740 | [br parms=clear="all"]
741 | [br can't touch this]
742 | [br parms=clear="all",or this either]
743 | [random seed=punt]
744 | [random seed=punt,icount=3]
745 | [mul mode=float,2 2]
746 | [div mode=float,10.0 3]
747 | [add mode=float,2 2.5]
748 | [sub mode=float,5 2.2]
749 | [month 3]
750 | [month mode=long,3]
751 | [style x [b] [ampm [b]] ]
752 | [for x,0,24,1]
753 | [style x [twelve [b]] ]
754 | [for x,0,24,1]
755 | Double locked-box encryption:
756 | [local x [encrypt seed=1234,This is a test]]
757 | [local x [encrypt seed=5678,again=1,[v x]]]
758 | [local x [encrypt seed=1234,again=1,[v x]]]
759 | last stage of mode 0:
760 | [v x]
761 | [decrypt seed=5678,[v x]]
762 | Double locked-box encryption, mode 1:
763 | [local x [encrypt seed=chump,mode=1,Test-tickle]]
764 | [local x [encrypt seed=can,mode=1,again=1,[v x]]]
765 | [local x [encrypt seed=chump,mode=1,again=1,[v x]]]
766 | Last stage of mode 1:
767 | [v x]
768 | [dict mtest,foo:1]
769 | [d mtest,foo]
770 | [d mtest,bar]
771 | [d mtest,bar,0]
772 | [d sep=|,mtest|foo]
773 | [d sep=|,mtest|bar]
774 | [d sep=|,mtest|bar|0]
775 | [decrypt seed=can,mode=1,[v x]]
776 | [crop words=true,col=41,this is a test of the emergency broadcast system. If this had been a real emergency, we would all be dead by now.]
777 | [collapse this is a test]
778 | [wwrap eol=|,40,This is a test of the emergency broadcast system. If this had
779 | been a real emergency, you would have been instructed to place your
780 | head between your legs and kiss your ass goodbye.
781 | |Or at least, you would have been instructed to go quiver underneath your
782 | bed while we sorted out how to break the news to you that your existence
783 | into the near future is in serious doubt.]
784 | [round 22.4]
785 | [round digits=1,22.44]
786 | [style help2=bugger,help=hooah,foo bar]
787 | [helps foo]
788 | [helps2 foo]
789 | [gstyle help2=pumpkin,help=yessir,bar foo]
790 | [helpg bar]
791 | [helpg2 bar]
792 | [term HTH]
793 | [term astyle=border-bottom:green dashed;,HTH]
794 | [ddelta 20180606 20180607]
795 | [locsplit pxv,|,abc|def|ghi]
796 | [v pxv0] [v pxv1] [v pxv2] [v pxv_splitcount]
797 | [glosplit nnq,|,jkl|mno|pqr]
798 | [v nnq0] [v nnq1] [v nnq2] [v nnq_splitcount]
799 |
--------------------------------------------------------------------------------
/martomac.README.md:
--------------------------------------------------------------------------------
1 | # [martomac.py](martomac.py) -- Markup to `Macro()` format converter
2 |
3 | use: `python martomac.py [options] markdownFile[.md] [macroFile]`
4 |
5 | ## Available options
6 |
7 | Option | Effect
8 | ------ | ------
9 | -t | generate `mtmtestfile.html` through `macro()`
10 | -o | open `mtmtestfile.html` in OS X default browser
11 | -c | do not prefix with built-in styles \(use your own\!\)
12 | -s | suppress generated blank lines between block elements
13 | -x | suppress filename report
14 | -p | output goes to stdout
15 | -l | strip tailing newlines from list elements
16 | -d | dump canned styles to file "cannedstyles.txt" for your reference
17 | -h | wraps content of "cannedstyles.txt" or stdout in basic HTML page
18 | -m macroFileName | provide your own styles that may override the canned styles
19 |
20 | ## Some Examples:
21 |
22 | ### Normal use:
23 |
24 | python martomac.py README.md
25 |
26 | Generates:
27 |
28 | Output | Contents | Errors
29 | -------|----------|-------
30 | file `README.txt` | file ready for input to macro\(\) | **stderr**
31 | **stdout** | Report of filename\(s\) to be used
32 | **stderr** | Errors
33 |
34 | ### With addional test file output:
35 |
36 | python martomac.py -t README.md
37 |
38 | Generates:
39 |
40 | Output | Contents
41 | -------|---------
42 | file `README.txt` | file ready for input to macro\(\)
43 | file `mtmtestfile.html` | output generated by macro\(\)
44 | **stdout** | Report of filename\(s\) to be used
45 | **stderr** | Errors
46 |
47 | ### Output convenient for pipes:
48 |
49 | python martomac.py -x -p README.md
50 |
51 | Generates:
52 |
53 | Output | Contents
54 | -------|---------
55 | **stdout** | text stream ready for input to macro\(\)
56 | **stderr** | Errors
57 |
58 | ### Generate and view output with your browser:
59 |
60 | python martomac.py -t -o -h -x README.md
61 |
62 | \(mtm.md is the test file I supply -- I'm still working
63 | on compatability with less masic use of markdown. Mostly
64 | it's order of parsing and the like.\)
65 |
66 | Output | Contents
67 | -------|---------
68 | mtmtestfile.html | Opens right in your OS X browser
69 | **stderr** | Errors
70 |
71 | ### Customizing your output:
72 |
73 | You can customize almost anything about the actual conversion
74 | process, because it's managed by styles; styles you can override.
75 |
76 | For instance:
77 |
78 | In the default set of `macro()` styles that are used to
79 | handle the markdown-to-macro conversion, there's a style
80 | that sets the color of code blocks. This is it:
81 |
82 | [style codewrap [color 080 [b]]]
83 |
84 | Now, perhaps you're prefer your code to be some other color or shade.
85 | Perhaps red. No problem. Using the `-m` option, you can supply a
86 | replacement for this \(or anything else you want to change about how the
87 | conversion is handled.\) Just create a file, I'll call this one
88 | `mycustommd.mac`, and put the replacement style in it:
89 |
90 | [style codewrap [color 800 [b]]]
91 |
92 | Now, when you invoke `martomac.py`, just add this to your command...
93 |
94 | -m mycustommd.mac
95 |
96 | ...and there you go. Red code.
97 |
98 | Of course, you can put far more in there than just color. You could
99 | set up a span with custom inline or cascaded CSS and do virtually
100 | anything you like.
101 |
102 | ### Better image handling
103 |
104 | Markdown doesn't handle width= and height= within an image tag,
105 | because it doesn't know squat about your image other than the
106 | web path that's in the url.
107 |
108 | `macro()` can be made to handle this properly, even in the context
109 | of a converted Github or markdown file. The default behavior within
110 | `martomac.py` is to not handle it, just like markdown. The image
111 | style that is in place by default is...
112 |
113 | [style img [split [co],[b]][img [parm 0],[urlencode [parm 1]]]]
114 |
115 | ...which just catches your URL from the markdown image spec,
116 | encodes it, and shoves it in the image as-is.
117 |
118 | So when you say `{img pics/mypic.jpg}`, you get this...
119 |
120 |
121 |
122 | ...and that's the end of that. And the web surfer's browser will snap and
123 | twitch and rejigger the page layout until it figures out the actual image
124 | size to be used. By reading the image once it downloads it. Yech.
125 | Just like Markdown.
126 |
127 | But if you take a moment to prepare a file with some overrides it it, you
128 | can avoid this. Let's say your images are in:
129 |
130 | /usr/www/svr.com/htdocs/pics/
131 |
132 | All you have to put in the override file \(see the -m option\) is...
133 |
134 | [lipath /usr/www/svr.com/htdocs/pics/]
135 | [style img [split [co],[b]][locimg [parm 0],[urlencode [parm 1]]]]
136 |
137 | ...now the conversion will use the new '{img}' style instead of the default,
138 | which utilizes the smarter `[locimg]` built-in, and it in turn will know
139 | where your images are, because you told it with
140 | the `[lipath]` built-in. So it opens them, checks them out, and viola,
141 | you get something like this:
142 |
143 |
144 |
145 | ### Readability
146 |
147 | In order to make this all work as a customizable conversion, I've used
148 | styles much more liberally than would be typical. The end result -- of
149 | the conversion, not the HTML -- is infested, as it were, with these
150 | styles. That's not how I normally write `macro()` source, nor do I
151 | expect it would be how others do so. There are *far* more effective and
152 | less wordy \(and more readable\) ways to accomplish all of this if
153 | you're writing it directly, rather than trying to parse out markdown
154 | text.
155 |
156 | So please don't be deterred by how the conversion results come out.
157 | If that was how things *had* to look in general, I wouldn't have bothered
158 | to write `macro()` in the first place.
159 |
160 | ## On Github's habit of Eating HTML tags
161 |
162 | Github eats many useful -- and harmless -- HTML tags. You can't specify
163 | a serif font, or a text color, or a whole raft of other things. The
164 | explanation is that these tags "might harm your documents" \(cough\)
165 |
166 | Markdown, however, doesn't do this, assuming that as the
167 | author / maintainer / arbiter of the document, you know what you're doing.
168 | Which - frankly - is the right thing to do. You write your own docs on Github,
169 | and if someone pushes something you didn't actually *check* and you accept it...
170 | well, your fault if your document becomes unreadable or weird looking, eh?
171 |
172 | There are a few exceptions -- scripts could be used by you as a blackhat
173 | with Github as the target, so yes, I can see why they'd kill those, but
174 | FFS, sometimes you need other things \(ever try to discern a capital
175 | letter I from a lower case L in Github's monospaced font? That kind of
176 | nonsense is why TT tags normally use a serif font in the first place.\)
177 |
178 | So. I **don't** take out your tags. Github processing or not. You should
179 | have control over what tags you have in there because you should *know*
180 | what tags you have in there.
181 |
182 | ## Note: Or, "Perl before Swine" \(*Oink!*\)
183 |
184 | This task would ideally have been accomplished by taking the Perl
185 | markdown-to-html generator and changing it to output a minimal subset of
186 | macro\(\) code, as that would result in a far higher quality conversion;
187 | one that does exactly what markdown does in the same contexts.
188 |
189 | But I don't code in Perl any longer. I actually downloaded and looked at
190 | the markdown Perl code, and all that did was profoundly re-affirm my
191 | decision not to code in Perl. It just doesn't suit the way my mind works.
192 |
193 | So. If someone else wants to go after this particular bit of fruit,
194 | which, if you're really into Perl, you might even find to be
195 | low-hanging, by all means do so and I'd be delighted to have it join the
196 | rest of this fluffy goodness.
197 |
198 | Otherwise you get my converter, which was seat-of-the-pants and only
199 | works properly within the context of precisely correct \(and still
200 | incomplete, see [todo.md](todo.md)\) markdown syntax. The markdown
201 | processor itself is pretty relaxed about unclosed italics and bold,
202 | unescaped special characters and so on. `martomac.py` is not.
203 |
204 | The downside of that is that even after I work through everything
205 | remaining on [todo.md](todo.md) some of your `.md` files may not convert
206 | correctly. In fact, if you manage to get unbalanced braces of any flavor
207 | in the .md file outside of a code block or span, or fail to escape them
208 | properly, the resulting `macro()` input will not be fully parsable,
209 | which will leave you with truncated HTML results.
210 |
211 | The upside is that it may tell you that you might need to fix your
212 | markdown. :\)
213 |
214 | On the *other* hand, if you find a conversion not working that you think
215 | should work, push the markdown file to the `aa_macro` repo and I will
216 | take a look -- or of course you can implement any fixes yourself, if you
217 | are so inclined.
218 |
219 | See the supplied [test file](mtm.md) and the other markdown files in the
220 | `aa_macro` repo here for a look at what is known to work.
221 |
222 |
--------------------------------------------------------------------------------
/martomac.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python
2 |
3 | # Convert markdown file source files to aa_macro source files
4 |
5 | import sys
6 | import os
7 | import re
8 | from aa_macro import *
9 |
10 | defs = """
11 | [local tablec bgcolor="#cccccc"]
12 | [local oddrowc bgcolor="#ffffff"]
13 | [local evenrowc bgcolor="#f4f4f4"]
14 | [local hdrrowc bgcolor="#ffffff"]
15 | [local codecolor 080]
16 | [local c1 [v oddrowc]]
17 | [local c2 [v evenrowc]]
18 | [local c 0]
19 | [style a [split [co],[b]][a [urlencode [parm 1]],[parm 0]]]
20 | [style ac [local c [inc [v c]]][odd [v c] [v c1]][even [v c] [v c2]]]
21 | [style ampersand &]
22 | [style asterisk *]
23 | [style b [b [b]]]
24 | [style blockquote [nl][b][nl]
]
25 | [style br
]
26 | [style codepre {nbsp}{nbsp}{nbsp}{nbsp}]
27 | [style code [split [co],[b]][b {codewrap [parm 1]
]}[comment parm 0]]
28 | [style fencecode [split [co],[b]][b [color [v codecolor] [parm 1]
]][comment parm 0]]
29 | [style codewrap {nobreak {greyback [color [v codecolor] [b]] }}]
30 | [style comma [co]]
31 | [style greyback [b]]
32 | [style gt >]
33 | [style h1 [b]
]
34 | [style h2 [b]
]
35 | [style h3 [b]]
36 | [style h4 [b]
]
37 | [style h5 [b]
]
38 | [style h6 [b]
]
39 | [style hcell [header [b]]]
40 | [style hrow [row [v hdrrowc],[b]]]
41 | [style i [i [b]]]
42 | [style img [split [co],[b]][img [parm 0],[urlencode [parm 1]]]]
43 | [style inline [b {codewrap [b]}]]
44 | [style la <]
45 | [style lb [lb]]
46 | [style ls [ls]]
47 | [style lt <]
48 | [style lparen (]
49 | [style rparen )]
50 | [style nbsp ]
51 | [style nobreak [b]]
52 | [style ra >]
53 | [style rb [rb]]
54 | [style ol [ol [b]]]
55 | [style p [p [nl][b][nl]]]
56 | [style quot "]
57 | [style row [row {ac},[b]]]
58 | [style rs [rs]]
59 | [style table [table style="border-collapse: collapse; border-spacing: 0px; border-width: 1px; border-style: solid;" cellpadding=10 cellspacing=0 border=1 [v tablec]",[b]]]
60 | [style tcell [cell [b]]]
61 | [style u [u [b]]]
62 | [style ul [ul [b]]]
63 | [style underline _]
64 | """
65 |
66 | ecape = { '[':'{lb}',']':'{rb}',
67 | '{':'{ls}','}':'{rs}',
68 | }
69 |
70 | def fourspacedetect(s):
71 | det = False
72 | if s[:4] == ' ':
73 | det = True
74 | for c in s:
75 | if c == ' ':
76 | pass
77 | elif c == '*':
78 | det = False
79 | break
80 | return det
81 |
82 | def cape(c):
83 | return ecape.get(c,c)
84 |
85 | def escapeForHTML(c):
86 | if c == '<': return '{lt}'
87 | if c == '>': return '{gt}'
88 | return c
89 |
90 | def rint(string,err=False,term='\n'):
91 | if err == True:
92 | sys.stderr.write(string+term)
93 | else:
94 | sys.stdout.write(string+term)
95 |
96 | testfilename = "mtmtestfile.html"
97 | canname = 'cannedstyles.txt'
98 |
99 | def help():
100 | rint('()=required, |= "or", []=optional')
101 | rint('USE: (python|./) martomac.py [-m macroFilename][-c ][-s ][-t ][-p ][-x ]inputFilename[.md] [outputFilename]')
102 | rint("-c flag suppresses leading default style definitions, supply your own")
103 | rint("-s flag suppresses blank lines between block elements")
104 | rint('-t flag creates macro() processed output test file "%s"' % (testfilename))
105 | rint('-h flag wraps content of "%s" or stdout in basic HTML page' % (testfilename,))
106 | rint('-x flag suppresses printing filename report')
107 | rint('-o open default OS X browser on "%s"' % (testfilename,))
108 | rint('-p flag routes normal output to stdout')
109 | rint('-l flag strips terminating newlines off of list elements')
110 | rint('-d flag dumps canned styles to the file "%s" for your reference' % (canname,))
111 | rint('-m macroFileName prefixes your styles, which can override the built-ins')
112 | raise SystemExit
113 |
114 | github = True
115 | usedefs = True
116 | maketest = False
117 | usestdout = False
118 | noreport = False
119 | lnlstrip = False
120 | wrapper = False
121 | openit = False
122 | whiteline = '\n'
123 | mfilename = ''
124 |
125 | argv = []
126 | lookformf = False
127 | for el in sys.argv:
128 | if el == '-c':
129 | usedefs = False
130 | elif el == '-o':
131 | openit = True
132 | elif el == '-l':
133 | lnlstrip = True
134 | elif el == '-p':
135 | usestdout = True
136 | elif el == '-x':
137 | noreport = True
138 | elif el == '-s':
139 | whiteline = ''
140 | elif el == '-h':
141 | wrapper = True
142 | elif el == '-d':
143 | try:
144 | fh = open(canname,'w')
145 | fh.write(defs)
146 | fh.close()
147 | except:
148 | rint('Could not write "%s" file',True)
149 | help()
150 | elif el == '-t':
151 | maketest = True
152 | elif el == '-m':
153 | lookformf = True
154 | else:
155 | if lookformf == False:
156 | argv += [el]
157 | else:
158 | lookformf = False
159 | mfilename = el
160 |
161 | usemfile = False
162 | if mfilename != '':
163 | try:
164 | fh = open(mfilename)
165 | except:
166 | rint('Cannot open macro file "%s"' % (mfilename,),True)
167 | help()
168 | else:
169 | fh.close()
170 | usemfile = True
171 |
172 | argc = len(argv)
173 | if argc != 2 and argc != 3:
174 | rint('Unexpected number of arguments: %d' % (argc-1),True)
175 | rint('args: %s' % (str(argv[1:])),True)
176 | help()
177 |
178 | ifn = argv[1]
179 |
180 | try:
181 | fh = open(ifn)
182 | except:
183 | tfn = ifn+'.md'
184 | try:
185 | fh = open(tfn)
186 | except:
187 | rint('Cannot open input file "%s" or "%s"' % (ifn,tfn),True)
188 | help()
189 | else:
190 | ifn = tfn
191 | fh.close()
192 |
193 | if argc == 3:
194 | ofn = argv[2]
195 | else:
196 | ofn = ifn.replace('.md','.txt')
197 |
198 | if noreport == False:
199 | rint(' Input File: "%s"' % (ifn,))
200 | rint('Output File: "%s"' % (ofn,))
201 |
202 | if usedefs == False:
203 | defs = ''
204 |
205 | if usemfile == True:
206 | fh = open(mfilename)
207 | chunk = fh.read()
208 | fh.close()
209 | defs += chunk
210 |
211 | # Markdown rules for HTML:
212 | # ------------------------
213 | # entities do NOT get ampersand replacement outside of code blocks and spans
214 | # code blocks DO get replacement of ampersands no matter what
215 | # quotes turn into entities EXCEPT inside HTML tags or when an angle-link is found...
216 | # ...might be able to punt by detecting entity/anglelink if post-this-operation...
217 | # ...and converting quot entities back to quotes inside tags, but bleaugh
218 | # <> are entities EXCEPT when HTML tag is in use, and...
219 | # ...HTML tags can only occur outside code blocks
220 | # -------------------
221 | def escapeHTML(line):
222 | return line
223 |
224 | o = defs
225 | to = ''
226 | prevline = ''
227 | blankline = False
228 | thispara = ''
229 |
230 | # change all underline-style header codes to #-stype header codes:
231 | pline = ''
232 |
233 | escBackslash = '6gg7HH8KK8fgh567'
234 | escBTick = 'lkjUYThgfREW'
235 | escAsterisk = 'hCpDo3Rk5EkS7'
236 | escUnderline = 'hY9gTf8RdO1lMjB'
237 | escLSquig = 'rFvtGbyHnuJm'
238 | escRSquig = 'XsWCdEVfRBgT'
239 | escLBrack = '7Y6t5R4e3W'
240 | escRBrack = '9O8i7U6y5T4r'
241 | escLParen = 'tskfuGFHFY'
242 | escRParen = 'HGYJoooiUhjTgR'
243 | escHash = '778hyFRgTcFzA'
244 | escPlus = 'hTTgfdDDerG'
245 | escMinus = 'iJJuGGtFFrDDwer'
246 | escDot = 'zLcImEbWpDqL'
247 | escXMark = 'poiASDlkjEWQ'
248 |
249 | liveComma = '6gT8fR9mY5bG'
250 |
251 | # Single chars to be ignored within code blocks
252 | # and spans. They only regenerate after macro()
253 | # ---------------------------------------------
254 | def charCleaner(c):
255 | if c == '&': c = '{ampersand}'
256 | elif c == '_': c = '{underline}'
257 | elif c == '*': c = '{asterisk}'
258 | elif c == '<': c = '{la}'
259 | elif c == '>': c = '{ra}'
260 | elif c == '[': c = '{lb}'
261 | elif c == ']': c = '{rb}'
262 | elif c == '(': c = '{lparen}'
263 | elif c == ')': c = '{rparen}'
264 | return c
265 |
266 | # This sets things up so that the .md will parse successfully,
267 | # which means that stuff that .md escapes has to pass through the
268 | # parser without modification, as well as the link syntax. That is:
269 | #
270 | # 1:`stuff` -- within backticks
271 | # 2: stuff, -- subsequent to four spaces at BOL
272 | # 3:``` -- between lines that 'fence' code with triple backticks
273 | # stuff
274 | # ```
275 | # 4: [stuff] -- the text for the link (not sure about this)
276 | # 5: (stuff) -- the links themselves
277 | # --------------------------------------------------------------
278 | tripleticker = False # first line enters in non-tripletick on state
279 | def cleanthings(s): # input is one line
280 | global tripleticker
281 | s = escapeHTML(s)
282 | o = ''
283 | dex = 0
284 | toff = False
285 | inp = False; inpg = False
286 | ins = False; insg = False
287 | btig = False;
288 | ttg = False;
289 |
290 | # 4 spaces gates the entire line
291 | # ------------------------------
292 | if fourspacedetect(s) == True: iscg = True
293 | else: iscg = False
294 |
295 | # fenced code gates lines between start-of-line ``` signals
296 | # ---------------------------------------------------------
297 | triples = False
298 | if line[:3] == '```':
299 | triples = True
300 | if tripleticker == True: # if on, turn it off BEFORE we process chars
301 | tripleticker = False
302 | toff = True
303 |
304 | for c in s:
305 | dex += 1
306 |
307 | # backticks aren't filtered unless escaped
308 | # so the gate doesn't lead and lag them
309 | # we eat them, too, EXCEPT if this is a triple-tick
310 | # line, in which case, they have to remain
311 | # for later parsing out of language specs
312 | # ----------------------------------------
313 | cston = False
314 | cstoff = False
315 | passthru = True # generally, we process all characters on every line, unless:::
316 | if c == '`':
317 | if btig == False: # turning on possible backtick code span
318 | btig = True
319 | cston = True
320 | if triples == False:
321 | passthru = False # ::: eat single backticks not on tripletick fence lines
322 | else: # turning off possible backtick code span
323 | btig = False
324 | cstoff = True
325 | if triples == False:
326 | passthru = False # ::: eat single backticks not on tripletick fence lines
327 |
328 | # Square brackets:
329 | # ----------------
330 | # * prior to a link, they are the linked text
331 | # * prior to an image, they are the title and alt field content
332 | # ---------------------------------------------------------------
333 | if (btig == False and # squares inside backticks are ignored
334 | tripleticker == False and # squares inside tripletick fences are ignored
335 | iscg == False): # squares on four-space lines are ignored
336 | if ins == True: insg = True # insg lags start of squares by one
337 | if c == '[': ins = True
338 | elif c == ']':
339 | ins = False
340 | insg = False # insg ends before closing square is processed
341 |
342 | # Parens:
343 | # -------
344 | # These contain a link
345 | # ------------------------------------------------------------------
346 | if (btig == False and # parens inside backticks are ignored
347 | tripleticker == False and # parens inside tripletick fences are ignored
348 | iscg == False): # parens on four-space lines are ignored
349 | if inp == True: inpg = True # inpg lags start of parens by one
350 | if c == '(': inp = True
351 | elif c == ')':
352 | inp = False
353 | inpg = False # inpg ends before closing paren is processed
354 |
355 | # Wrap {inline } around backticks. This
356 | # wrap happens outside the character check
357 | # so it will pass through without escaping
358 | # ----------------------------------------
359 | if ( triples == False and # not on triple tick line
360 | inpg == False and # not within parens
361 | insg == False and # not within square brackets
362 | iscg == False and # not on four-space line
363 | tripleticker == False): # not within tripletick fences
364 | if (btig == True and # if in backtick zone
365 | cston == True): # and it just turned on
366 | o += '{inline ' # THEN open {inline
367 | if cstoff == True: # if it just turned off
368 | o += '}' # THEN close {inline ...}
369 |
370 | if (inpg == True or # if in paren zone, or
371 | insg == True or # if in square bracket zone, or
372 | iscg == True or # if on four-space line, or
373 | btig == True or # if within backticks, or
374 | tripleticker == True): # if within triple-tick fences
375 | c = charCleaner(c) # THEN escape: &_*<>[]()
376 |
377 | # Although markdown provides escapes for {}, it is unclear why
378 | # ------------------------------------------------------------
379 | if c == '{': c = '{ls}' # escape { -- these must pass through, period
380 | elif c == '}': c = '{rs}' # escape }
381 |
382 | if passthru == True: # if we're not eating this character or replacement:
383 | o += c # THEN add it to the output
384 |
385 | # turn on code filter mode AFTER we process chars
386 | if (line[:3] == '```' and # if tripletick line
387 | toff == False and # and if we didn't turn off tripleticks already
388 | tripleticker == False): # and if it's off right now
389 | tripleticker = True # THEN turn it on
390 | return o
391 |
392 | # This runs very first thing
393 | # --------------------------
394 | def smartEscape(line):
395 | global escUnderline
396 | global escAsterisk
397 | global liveComma
398 | global escLParen
399 | global escRParen
400 | global escLBrack
401 | global escRBrack
402 | global escLSquig
403 | global escRSquig
404 | global escXMark
405 | global escBackslash
406 | global escHash
407 | global escBTick
408 | global escPlus
409 | global escMinus
410 | global escDot
411 |
412 | # An escaped character means that .md does not see it. The
413 | # question remaining at this time is, what does a backslash
414 | # escape mean within the context of a code block? Find out. TODO
415 | # ---------------------------------------------------------
416 | line = line.replace(r'\#',escHash)
417 | line = line.replace(r'\_',escUnderline)
418 | line = line.replace(r'\*',escAsterisk)
419 | line = line.replace(r'\(',escLParen)
420 |
421 | line = line.replace(r'\]',escRBrack)
422 | line = line.replace(r'\[',escLBrack)
423 |
424 | line = line.replace(r'\}',escRSquig)
425 | line = line.replace(r'\{',escLSquig)
426 |
427 | line = line.replace(r'}',escRSquig)
428 | line = line.replace(r'{',escLSquig)
429 |
430 | line = line.replace(r'\)',escRParen)
431 | line = line.replace(r'\(',escLParen)
432 |
433 | line = line.replace(r'\\',escBackslash)
434 | line = line.replace(r'\+',escPlus)
435 | line = line.replace(r'\-',escMinus)
436 | line = line.replace(r'\.',escDot)
437 | line = line.replace(r'\!',escXMark)
438 | line = line.replace(r'\`',escBTick)
439 | line = line.replace(r',',liveComma) # commas mean nothing to .md, but they mean something to mac
440 |
441 | line = line.replace('\t',' ')
442 |
443 | line = cleanthings(line)
444 | return line
445 |
446 | # This runs after md --> mac, but prior to mac --> HTML
447 | # -----------------------------------------------------
448 | def smartUnEscape(s):
449 | global escUnderline
450 | global escPlus
451 | global escMinus
452 | global escDot
453 | global escAsterisk
454 | global liveComma
455 | global escLParen
456 | global escRParen
457 | global escLBrack
458 | global escRBrack
459 | global escLSquig
460 | global escBackslash
461 | global escRSquig
462 | global escXMark
463 | global escHash
464 | global escBTick
465 | s = s.replace(escHash,'#')
466 | s = s.replace(escXMark,'!')
467 | s = s.replace(escUnderline, '_')
468 | s = s.replace(escAsterisk, '*')
469 | s = s.replace(liveComma, '{comma}')
470 | s = s.replace(escLParen, '(')
471 | s = s.replace(escRParen, ')')
472 | s = s.replace(escLBrack, '{lb}')
473 | s = s.replace(escRBrack, '{rb}')
474 | s = s.replace(escLSquig, '{ls}')
475 | s = s.replace(escRSquig, '{rs}')
476 | s = s.replace(escBTick, '`')
477 | s = s.replace(escBackslash, '\\')
478 | s = s.replace(escPlus, '+')
479 | s = s.replace(escMinus, '-')
480 | s = s.replace(escDot, '.')
481 | return s
482 |
483 | ysource = []
484 | lc = 0
485 | try:
486 | ifh = open(ifn)
487 | except:
488 | rint('Could not open input file "%s"' % (ifn,),True)
489 | help()
490 | else:
491 | try:
492 | for line in ifh:
493 | lc += 1
494 | try:
495 | line = smartEscape(line)
496 | except Exception,e:
497 | rint('blew up %s' % str(e),True)
498 | ysource += [line]
499 | except:
500 | rint('Could not read input file "%s" (%d lines read)' % (ifn,lc),True)
501 | try:
502 | ifh.close()
503 | except:
504 | rint('Could not close input file "%s"' % (ifn,),True)
505 | help()
506 | else:
507 | try:
508 | ifh.close()
509 | except:
510 | rint('Could not close input file "%s"' % (ifn,),True)
511 | help()
512 |
513 |
514 |
515 | xsource = []
516 | tflag = -1
517 | killkey = 'jncfvs8jn2247y8fajn0'
518 | for line in ysource:
519 | if line[:3] == '---': # this can also indicate a table header/body interspersal
520 | if github == True: # then we can look for tables
521 | if line.find(' | ') > 0: # we throw out table header-body lines as unneeded
522 | line = killkey
523 | xsource += [pline]
524 | else:
525 | line = '# ' + pline # convert setex style to atx title line
526 | pline = ''
527 | else: # not github, just do titles
528 | line = '# ' + pline # title line
529 | pline = ''
530 | elif line[0] == '=':
531 | line = '## ' + pline # convert setex style to atx title line
532 | pline = ''
533 | else:
534 | if pline != killkey:
535 | xsource += [pline]
536 | pline = line
537 |
538 | xsource += [pline]
539 | xsource += ['\n']
540 |
541 | # Escape all the characters that drive macro():
542 | # ---------------------------------------------
543 | source = []
544 | tmode = -1
545 | pipekey = 'nMbVc4GhItR'
546 | prctkey = 'uHyGt9FrDeS'
547 | for line in xsource:
548 | droptag = ''
549 | floptag = ''
550 | if github == True and line.find(' | ') > 0:
551 | tline = ''
552 | line = line.replace(r'\|',pipekey) # bury any escaped |'s
553 | line = line.replace(',','{comma}') # intern commas -- we use 'em
554 | if tmode == -1: # header row?
555 | celltype = 'hcell'
556 | rowtype = 'hrow'
557 | tmode += 1 # now zero
558 | tline += '{table '
559 | else: # normal row
560 | celltype = 'tcell'
561 | rowtype = 'row'
562 | tmode += 1 # first line is #1 -- can pass out counter later
563 | celllist = line.split('|')
564 | tline += '{%s ' % (rowtype,)
565 | for cell in celllist:
566 | cell = cell.replace('%',prctkey) # bury any existing %'s
567 | cell = cell.strip()
568 | asm = '{%s '+cell+'}'
569 | asm = asm % (celltype,)
570 | asm = asm.replace(prctkey,'%') # restore % signs
571 | asm = asm.replace(pipekey,r'\|') # restore escaped |'s
572 | tline += asm # add the cell to the line
573 | tline += '}' # close the row
574 | line = tline
575 | else:
576 | if tmode != -1: # were we in a table?
577 | tmode = -1 # then bail
578 | floptag += '}\n' # close the table
579 |
580 | if floptag != '':
581 | source[-1] = source[-1] + floptag
582 | source += ['\n']
583 | source += [line]
584 |
585 | OUTSTATE = 0
586 | PARASTATE = 1
587 | QUOTESTATE = 2
588 | BOLDSTATE = 3
589 | ITALICSTATE = 4
590 | UNDERLINESTATE = 5
591 | CODESTATE = 6
592 |
593 | # parser for header-converted lines
594 | # ---------------------------------
595 | pstate = OUTSTATE
596 | qstate = OUTSTATE
597 | bstate = OUTSTATE
598 | istate = OUTSTATE
599 | ustate = OUTSTATE
600 | cstate = OUTSTATE
601 | wl = whiteline
602 |
603 | urldex = 1
604 | verbdex = 1
605 | urlcode = '8gYfTdRsE4'
606 | verbcode = '3cDvFbGnH9'
607 | urlstash = {}
608 | verbstash = {}
609 |
610 | tabsize = 4
611 |
612 | fiin = False
613 | fbin = False
614 |
615 | def emphasis(s):
616 | global fiin
617 | global fbin
618 | bcmd = '7rfmnKIgf'
619 | icmd = '9jtGVfrDC'
620 | s = s.replace('**',bcmd)
621 | s = s.replace('__',bcmd)
622 | s = s.replace('*',icmd)
623 | s = s.replace('_',icmd)
624 | run = True
625 | while run == True:
626 | run = False
627 | if s.find(bcmd) != -1:
628 | run = True
629 | if fbin == False:
630 | fbin = True
631 | s = s.replace(bcmd,'{b ',1)
632 | else:
633 | fbin = False
634 | s = s.replace(bcmd,'}',1)
635 | run = True
636 | while run == True:
637 | run = False
638 | if s.find(icmd) != -1:
639 | run = True
640 | if fiin == False:
641 | fiin = True
642 | s = s.replace(icmd,'{i ',1)
643 | else:
644 | fiin = False
645 | s = s.replace(icmd,'}',1)
646 | return s
647 |
648 | def oemphasis(s):
649 | reject = r'([^\s\n\t])' # anything but a space, tab or return
650 |
651 | if 1:
652 | pat = r'([^\\])\*\*' + reject # leading **
653 | repl = r'\1{b \2'
654 | s = re.sub(pat,repl,s)
655 |
656 | if 1:
657 | pat = r'([^\\])\_\_' + reject # leading __
658 | repl = r'\1{b \2'
659 | s = re.sub(pat,repl,s)
660 |
661 | if 1:
662 | pat = reject + r'\*\*' # trailing **
663 | repl = r'\1}'
664 | s = re.sub(pat,repl,s)
665 |
666 | if 1:
667 | pat = reject + r'\_\_' # trailing __
668 | repl = r'\1}'
669 | s = re.sub(pat,repl,s)
670 |
671 | if 1:
672 | pat = reject + r'\*' # trailing *
673 | repl = r'\1}'
674 | s = re.sub(pat,repl,s)
675 |
676 | if 1:
677 | pat = reject + r'\_' # trailing _
678 | repl = r'\1}'
679 | s = re.sub(pat,repl,s)
680 | if 1:
681 | pat = r'([^\\])\*' + reject # leading *
682 | repl = r'\1{i \2'
683 | s = re.sub(pat,repl,s)
684 |
685 | if 1:
686 | pat = r'([^\\])\_' + reject # leading _
687 | repl = r'\1{i \2'
688 | s = re.sub(pat,repl,s)
689 |
690 | return s
691 |
692 | def checklist(line):
693 | tabsize = 4
694 | depth = 0
695 | mstring = ''
696 | listtype = None
697 | listmode = False
698 | ll = len(line)
699 | for i in range(0,ll):
700 | c = line[i]
701 | if c == ' ':
702 | depth += 1
703 | elif c == '\t':
704 | depth += tabsize
705 | elif c >= '0' and c <= '9':
706 | if line[i+1:i+3] == ') ':
707 | listmode = True
708 | listtype = 0
709 | mstring = c+') '
710 | break
711 | elif line[i:i+2] == '* ':
712 | listmode = True
713 | listtype = 1
714 | mstring = '* '
715 | break
716 | else:
717 | break
718 | return listmode,listtype,depth,mstring
719 |
720 | def makelists(lstack):
721 | global lnlstrip
722 | lmode = -1
723 | lo = ''
724 | deep = 0
725 | depth = -1
726 | for lel in lstack:
727 | ltype = lel[0]
728 | lline = lel[1]
729 | ldepth= lel[2]
730 | lline = lline.replace(',','{comma}')
731 | lline = lline.lstrip()
732 | if lnlstrip == True:
733 | lline = lline.rstrip()
734 | if ldepth > depth: # new list, deeper
735 | deep += 1
736 | lbreak = ''
737 | if deep > 1:
738 | lbreak = '\n'
739 | if ltype == 0: lo += lbreak+'{ol ' + lline
740 | else: lo += lbreak+'{ul ' + lline
741 | elif ldepth < depth: # previous list, shallower
742 | lo += '}\n'
743 | deep -= 1
744 | lo += ','+lline
745 | else: # same list
746 | lo += ','+lline
747 | depth = ldepth
748 | while deep > 0:
749 | lo += '}\n'
750 | deep -= 1
751 | return lo
752 |
753 | def inlinecode(line):
754 | state = 0
755 | oline = ''
756 | trigger = 0
757 | ll = len(line)
758 | for i in range(0,ll):
759 | c = line[i]
760 | if state == 0: # not inside backticks
761 | if line[i:i+2] == r' `':
762 | trigger = 1
763 | oline += c
764 | elif c == r'`' and trigger == 1:
765 | trigger = 0
766 | oline += '{inline '
767 | state = 1
768 | else:
769 | trigger = 0
770 | oline += c
771 | else: # inside backticks
772 | if c == r'`':
773 | oline += '}'
774 | state = 0
775 | else:
776 | c = escapeForHTML(c)
777 | oline += c
778 | return oline
779 |
780 | def fourspacecode(line):
781 | consume = False
782 | if fourspacedetect(line) == True:
783 | line = line.replace(' ','{codepre}',1)
784 | line = '{inline '+line.rstrip()+'}\n'
785 | consume = True
786 | return consume,line
787 |
788 | listmode = False
789 | liststack = []
790 | lastline4space = False
791 |
792 | for line in source:
793 | llen = len(line)
794 | blankline = False
795 | consume = False
796 | breakpara = False
797 | if line.strip() == '': # detect blank lines -- they terminate paras, quotes if open
798 | blankline = True
799 | lastline4space = False
800 | line = ''
801 | else: # this is not a blank line
802 | if cstate == OUTSTATE:
803 | line = line.replace(' \n','{br}\n') # auto-append line breaks
804 | else:
805 | if line[:3] != '```':
806 | line = '{codepre}'+line
807 |
808 | c,line = fourspacecode(line)
809 | if c == True: # this is a fourspace line
810 | if lastline4space != False: # if the previous line wasn't a fourspace, we break paras
811 | line = '{br}'+line
812 | lastline4space = True # indicate last line state (not used again in this loop)
813 | else:
814 | lastline4space = False # indicate last line state (not used again in this loop)
815 |
816 | # Handle headers
817 | for i in range(6,0,-1):
818 | if line[:i] == '#' * i:
819 | hc = line[i:].strip()
820 | h = '\n{h%d %s}\n%s' % (i,hc,wl)
821 | line = h
822 | consume = True
823 |
824 | if line[:2] == '> ': # init or continue quote state
825 | if qstate != QUOTESTATE:
826 | qstate = QUOTESTATE
827 | line = '{blockquote %s' % (line[2:],)
828 | consume = True
829 | breakpara = True
830 |
831 | if github == True:
832 | if line[:3] == '```':
833 | blankline = True
834 | if cstate == OUTSTATE:
835 | cstate = CODESTATE
836 | lang = line.rstrip()[3:]
837 | if lang == '':
838 | lang = 'raw'
839 | line = '{fencecode %s,' % (lang,)
840 | consume = True
841 | breakpara = True
842 | else:
843 | cstate = OUTSTATE
844 | line = '}\n'
845 |
846 | # Tables cannot signal begin para or quote
847 | # ----------------------------------------
848 | if line.find('{row ') >= 0:
849 | consume = True
850 |
851 | # list processing:
852 | # ----------------
853 | lmode,ltype,depth,mstring = checklist(line)
854 | if listmode == False: # IF not presently in list mode
855 | if lmode == True: # IF we need to switch to list mode
856 | listmode = True
857 | line = line.replace(mstring,'',1)
858 | liststack += [[ltype,line,depth]]
859 | line = ''
860 | blankline = True
861 | else: # ELSE already in list mode
862 | if lmode == True: # IF still in list mode
863 | line = line.replace(mstring,'',1)
864 | liststack += [[ltype,line,depth]]
865 | line = ''
866 | blankline = True
867 | else: # ELSE in, but may need to get out
868 | if blankline != True:
869 | tmp = liststack[-1] # Get current list element
870 | ltype,txt,dep = tmp # unpack
871 | txt = txt + line # append the current line
872 | tmp = [ltype,txt,dep] # repack
873 | liststack[-1] = tmp # replace list element
874 | line = '' # line consumed in list
875 | blankline = True # don't process this (consume?)
876 | else: # we're done
877 | o += makelists(liststack)
878 | liststack = []
879 | listmode = False
880 |
881 | line = emphasis(line)
882 |
883 | # Cannot trip paras when...
884 | # 1) table is in scope
885 | # 2) fenced code is in scope because uses
886 | # -----------------------------------------------------
887 | if consume == False:
888 | if blankline == False:
889 | if cstate == OUTSTATE:
890 | if qstate == OUTSTATE:
891 | if pstate != PARASTATE:
892 | pstate = PARASTATE
893 | line = '{p %s' % (line,)
894 |
895 | if pstate == PARASTATE:
896 | # Paragraphs end when...
897 | # 1) four-space code is initiated
898 | # 2) a blank line is encountered
899 | # --------------------------------------------------------------
900 | if (breakpara == True or
901 | blankline == True):
902 | pstate = OUTSTATE
903 | if o[-1] == '\n':
904 | o = o[:-1]
905 | line += '}\n%s' % (wl,) # close para
906 |
907 | if qstate == QUOTESTATE:
908 | # Quotes end when...
909 | # a blank line is encountered
910 | # --------------------------------------------------------------
911 | if (blankline == True):
912 | qstate = OUTSTATE
913 | if o[-1] == '\n':
914 | o = o[:-1]
915 | line += '}\n%s' % (wl,) # close quote
916 |
917 | # look for images:
918 | tl = ''
919 | escape = False
920 | imagestate = 0
921 | linkstate = 0
922 | verbiagestate = 0
923 | verb = ''
924 | url = ''
925 | for c in line:
926 | if 1:
927 | if 1:
928 | if c == '!': # image introducer?
929 | imagestate = 1
930 | elif c == '[': # verbiage introducer?
931 | verb = ''
932 | verbiagestate = 1
933 | elif c == ']': # done with verbiage?
934 | verbiagestate = 0
935 | elif c == '(': # url introducer?
936 | url = ''
937 | linkstate = 1
938 | elif c == ')': # done with url?
939 | if url == '': # apparently, just some hanging parens
940 | tl += '()' # throw em back like the dead fish they are
941 | imagestate = 0
942 | linkstate = 0
943 | else:
944 | vcode = '%s%d' % (verbcode,verbdex)
945 | ucode = '%s%d' % (urlcode,urldex)
946 | verbdex += 1
947 | urldex += 1
948 | urlstash[ucode] = url
949 | verbstash[vcode] = verb
950 | if imagestate == 1: # was this an image?
951 | tl += '{img %s,%s}' % (vcode,ucode)
952 | else: # nope, hadda be a link
953 | tl += '{a %s,%s}' % (vcode,ucode)
954 | imagestate = 0
955 | linkstate = 0
956 | else: # incoming!
957 | if linkstate == 1:
958 | url += c
959 | elif verbiagestate == 1:
960 | verb += c
961 | else: # it's just a character
962 | tl += c
963 | line = tl
964 |
965 | o += line
966 |
967 | if fiin == True:
968 | o += '}'
969 | if fbin == True:
970 | o += '}'
971 |
972 | # Every line read; close any open states
973 | if cstate == CODESTATE:
974 | if o[-1] == '\n':
975 | o = o[:-1]
976 | o += '}\n'
977 |
978 | if qstate == QUOTESTATE:
979 | if o[-1] == '\n':
980 | o = o[:-1]
981 | o += '}\n'
982 |
983 | if pstate == PARASTATE:
984 | if o[-1] == '\n':
985 | o = o[:-1]
986 | o += '}\n'
987 |
988 | # Here, we replace raw URLs that are floating around the document:
989 | # ----------------------------------------------------------------
990 | pat = r'([hH][tT][tT][pP]\:\/\/.*?)\s'
991 | repl = '{a \\1,\\1} '
992 | o = re.sub(pat,repl,o)
993 |
994 | # Then we replace the url and verb codes with the actual urls and verbs
995 | # ---------------------------------------------------------------------
996 | for key in verbstash.keys():
997 | o = o.replace(key,verbstash[key])
998 | for key in urlstash.keys():
999 | o = o.replace(key,urlstash[key])
1000 |
1001 | # restore escaped characters
1002 | o = smartUnEscape(o)
1003 |
1004 | if wrapper == True:
1005 | o = """
1006 |
1007 | macro() HTML test output page
1008 |
1009 |
1010 | %s
1011 |
1012 |
1013 | """ % (o,)
1014 |
1015 | if usestdout == True:
1016 | rint(o)
1017 | else:
1018 | ok = True
1019 | try:
1020 | ofh = open(ofn,'w')
1021 | except:
1022 | rint('Cannot open output file "%s"' % (ifn,),True)
1023 | help()
1024 |
1025 | try:
1026 | ofh.write(o)
1027 | except:
1028 | rint('ERROR: Could not complete write to "%s"' % (ofn,),True)
1029 | ok = False
1030 | try:
1031 | ofh.close()
1032 | except:
1033 | rint('ERROR: Could not close "%s"' % (ofn,),True)
1034 | ok = False
1035 |
1036 | if maketest == True:
1037 | mod = macro()
1038 | oo = mod.do(o)
1039 | ok = True
1040 | try:
1041 | fh = open(testfilename,'w')
1042 | except:
1043 | rint('ERROR: Could not open "%s"' % (testfilename,),True)
1044 | ok = False
1045 | else:
1046 | try:
1047 | fh.write(oo)
1048 | except:
1049 | rint('ERROR: Could not complete write to "%s"' % (testfilename,),True)
1050 | ok = False
1051 | try:
1052 | fh.close()
1053 | except:
1054 | rint('ERROR: Could not close "%s"' % (tetsfilename,),True)
1055 | ok = False
1056 | if ok == True:
1057 | if openit == True:
1058 | cmd = 'open %s' % (testfilename)
1059 | os.system(cmd)
1060 |
--------------------------------------------------------------------------------
/mtm.md:
--------------------------------------------------------------------------------
1 | # Markdown-to-macro() Filter
2 |
3 | ## Paragraphs, escapes, empty parens
4 |
5 | Might be nice to be able to take a file that's been written in markdown format
6 | and output it as compatible source for macro()
7 |
8 | This would allow someone who has previously created some number of documents
9 | to convert them easily, while making available to them the many advantages
10 | that macro() has to offer. \(This is not a link\) and \[I am not square\]
11 |
12 | Linking
13 | =======
14 |
15 | This line has a link next [My Link](http://fyngyrz.com) and then more text.
16 |
17 | ### Sort-of linking: Images
18 |
19 | Whereas this line has an image next  and then additional text
20 |
21 | ### Raw URL
22 |
23 | And this is a raw url http://datapipe-blackbeltsystems.com right back there
24 |
25 | ## Emphasis
26 |
27 | Here comes **some bold text** and then *italic text* followed
28 | by some more __bold text__ and another bit of _italic text_.
29 | Which, not being modest, we will follow with some **bold _and italic_ text**
30 | and in fact, we'll **do it _twice_.** And then **_there is this,_** quite seriously.
31 | Now we'll **break across
32 | two lines** and _then do
33 | it again_ as we are just that kind of line-breaker.
34 |
35 | ## Lists
36 |
37 | Unordered:
38 |
39 | * single level
40 | * very simple
41 | * hopefully, anyway
42 |
43 | Ordered:
44 |
45 | 1) one
46 | 2) dos
47 | 3) III
48 |
49 | Unordered with unordered sublist
50 |
51 | * line one
52 | * line two
53 | * subline 1
54 | * subline 2
55 | * line three
56 |
57 | ## Code
58 |
59 | ### Fenced code:
60 |
61 | ```
62 | org $0100
63 | toport lda 0,x++
64 | sta >ioport
65 | bne toport
66 | rts
67 | ```
68 |
69 | Now for some HTML fenced code:
70 |
71 | ```
72 |
73 | paragraph content goes here
74 |
75 | ```
76 |
77 | ### In-line code:
78 |
79 | Here is some code: `macro()` and that's the end of it,
80 | or at least, hopefully.
81 |
82 | This stuff has tags: `foo
`
83 |
84 | ### Four-space indent code:
85 |
86 | This is not indented four spaces.
87 | Neither is this
88 |
89 | But this is
90 | as is this
91 | and this
92 |
93 | But not this.
94 |
95 | ## Tables
96 |
97 | header 1 | header two
98 | -------- | ----------
99 | cell a | cell B
100 | cell III | cell quatro
101 |
--------------------------------------------------------------------------------
/mycustommd.mac:
--------------------------------------------------------------------------------
1 | [style codewrap [color 800 [b]]]
2 |
--------------------------------------------------------------------------------
/plugin_demo.c:
--------------------------------------------------------------------------------
1 | // plugin_demo.c
2 | // -------------
3 | // tab stops every 4 spaces
4 |
5 | #include
6 | #include
7 | #include "developer.h"
8 |
9 | void pengine(struct plug *p,long start,long finish,struct pkg *(*service)(struct req *p)) // sets 64K remap
10 | {
11 | long i,v,b;
12 |
13 | b = (p->f[0] - 100.0f) * 655.35f; // b is now [-65535...65535]
14 | for (i = start; i < finish; i++) // we set this range to [0...65536]
15 | {
16 | v = i + b; // temp brightness adjust;
17 | if (v < 0) v = 0; // now limit remap range...
18 | if (v > 65535) v = 65535; // ...to acceptable bounds
19 | p->lr[i] = v; // install in remap channel
20 | }
21 | }
22 |
23 | void dengine(struct plug *p,long start,long finish,struct pkg *(*service)(struct req *p)) // generates output
24 | {
25 | long i;
26 |
27 | for (i = start; i < finish; i++) // 1-dimensional pixel processing
28 | {
29 | p->sr[i] = p->lr[p->mr[i]]; // remap pixel brightness
30 | p->sg[i] = p->lr[p->mg[i]]; // ...using 64k table in layer
31 | p->sb[i] = p->lr[p->mb[i]]; // ...
32 | }
33 | }
34 |
35 | void setup(struct plugin *p) // NOTE: most struct elements are preset to 0,
36 | { // if that is the setting you need, it's there.
37 | #include "ak_pu_date.txt" // this inserts the current date in the plugin
38 |
39 | p->layer_pri = 9500; // layer priority (posit in fx stack - see developer.h)
40 | strcpy(p->panel.n,"Brightness"); // name appearing on panel
41 | p->pthread[0] = 1; // plugin desires pengine() threading
42 | p->prange_methods[0]= 2; // custom range for pengine()
43 | p->pfinish[0] = 65536; // end+1 range for pengine() to process
44 | p->dthread[0] = 1; // plugin desires dengine() threading
45 | p->promotable = 1; // BUT user can add alpha, paint
46 | p->req_lr = 65536; // we'd like 1 layer of this size in lr
47 | p->slider_req = 1; // we'd like 1 slider (#0)
48 | strcpy(p->sliders[0].n,"Intensity");// legend for slider
49 | p->forder[0] = 20; // position on line zero
50 | p->svalues[0] = 100.0f; // initial value
51 | p->zvalues[0] = 200.0f; // initial hi value (user settable)
52 | p->ticks[0] = 21; // Ten ticks per hundred
53 | } // (low values default to 0.0f)
54 |
55 | void init(struct plug *pl,struct pkg *(*service)(struct req *p)) // called before pengine() and dengine()
56 | {
57 | struct req r;
58 | struct pkg *p;
59 | char *msg = "demo plugin init";
60 | // the following just demonstrates using the service function
61 | r.svc = REQ_STATUS; // request status line message service
62 | r.p1 = msg; // set up request with proper parameter
63 | p = service(&r); // send msg to status line, get package back
64 | }
65 |
66 | void cleanup(struct plug *pl,struct pkg *(*service)(struct req *p)) // called after all pengine() and dengine threads complete
67 | {
68 | struct req r;
69 | struct pkg *p;
70 | char *msg = "demo plugin cleanup";
71 | // the following just demonstrates using the service function
72 | r.svc = REQ_STATUS; // request status line message service
73 | r.p1 = msg; // set up request with proper parameter
74 | p = service(&r); // send msg to status line, get package back
75 | }
76 |
--------------------------------------------------------------------------------
/qr_html.txt:
--------------------------------------------------------------------------------
1 | [style h1 [b]
]
2 | [style h2 [b]
]
3 | [style # [comment [b]]]
4 | [style page
5 |
6 |
7 | Macro() Quick Reference
8 |
9 |
10 | [b]
11 |
12 |
13 | ]
14 |
15 | [style p [p [b]]]
16 | [style b [b [b]]]
17 | [style i [i [b]]]
18 | [style tt [b]]
19 |
20 | [style table [table [b]]]
21 | [style table2 [table [b]]]
22 |
23 | [style lb [color 0ff [lb]]]
24 | [style rb [color 0ff [rb]]]
25 | [style co [co]]
26 | [style vb [vb]]
27 | [style q "]
28 |
29 | [local toggle 0]
30 | [style ac
31 | [local toggle [inc [v toggle]]]
32 | [even [v toggle] 181818]
33 | [odd [v toggle] 000000]
34 | ]
35 |
36 | [style rezero [local toggle 0]]
37 |
38 | [style bistyle
39 | [splitcount 1][split ~,[b]][local tx [parm 1]]
40 | [ifge style=rezero,[len [v tx]],1,[row [header colspan=2, ]][row [header bgcolor="#444444" colspan=2,[color 0ff [v tx]]]][nl]]
41 | [row bgcolor="#{ac}",[splitcount 1][split |,[parm 0]][cell {tt {lb}[parm 0]{rb}}][cell [parm 1]]]
42 | ]
43 |
44 | [style bxstyle
45 | [splitcount 1][split ~,[b]][local tx [parm 1]]
46 | [row [splitcount 1][split |,[parm 0]][cell {tt {lb}[parm 0]{rb}}][cell [parm 1]]]
47 | ]
48 |
49 | [style c [b [color FF0 content]]]{# "content"}
50 | [style cc [b [color FF0 [b]]]]{# content}
51 | [style o [b [color f00 [b]]]]{# optional parameters}
52 | [style r [b [color 0F0 [b]]]]{# required parameters}
53 |
54 |
--------------------------------------------------------------------------------
/qr_markdown.txt:
--------------------------------------------------------------------------------
1 | [style h1 # [b]]
2 | [style h2 ## [b]]
3 | [style # [comment [b]]]
4 | [style page [b]]
5 |
6 | [style p [b][nl]]
7 | [style b **[b]**]
8 | [style i _[b]_]
9 | [style tt [b]]
10 |
11 | [style lb [lb]]
12 | [style rb [rb]]
13 | [style co [co]]
14 | [style vb [vb]]]
15 | [style q "]
16 |
17 | [local toggle 0]
18 | [style ac
19 | [local toggle [inc [v toggle]]]
20 | [even [v toggle] 181818]
21 | [odd [v toggle] 000000]
22 | ]
23 |
24 | [style rezero [local toggle 0]]
25 |
26 | [style table [b]]
27 | [local t2t Built-in]
28 | [style table2 [v t2t] | [nl][dup [len [v t2t]],-] | ----[b]]
29 |
30 | [style tinter [dup [len [parm 1]],-] | ----[nl]]
31 |
32 | [style bistyle
33 | [splitcount 1][split ~,[b]][local tx [parm 1]]
34 | [ifge style=rezero,[len [v tx]],1,[nl][v tx] | [nl]{tinter}]
35 | [splitcount 1][split |,[parm 0]] {tt {lb}[parm 0]{rb}} | [parm 1]
36 | ]
37 |
38 | [style bxstyle
39 | [splitcount 1][split ~,[b]][local tx [parm 1]]
40 | [splitcount 1][split |,[parm 0]] {tt {lb}[parm 0]{rb}} | [parm 1]
41 | ]
42 |
43 | [style c content]{# "content"}
44 | [style cc [b]]{# content}
45 | [style o \([b]\)]{# optional parameters}
46 | [style r **[b]**]{# required parameters}
47 |
48 |
--------------------------------------------------------------------------------
/quickref.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 | # Macro() BETA Quick Reference
13 | ## Functional Groupings
14 |
15 |
16 | _key:_ built-in \(options\) **required** content
17 |
18 |
19 |
20 | HTML Text Styling |
21 | ----------------- | ----
22 | [p content] | HTML paragraph
23 | [bq content] | HTML blockquote
24 | [b content] | HTML bold
25 | [i content] | HTML italics
26 | [u content] | HTML underline
27 | [color **HEX3|HEX6** content] | HTML text color
28 |
29 | HTML Linking |
30 | ------------ | ----
31 | [a \(tab,\)**URL**\(,linkedContent\)] | HTML link
32 | [urlencode **content**] | URL encoding
33 | [url \(sep=|,\)\(css=CSS,\)\(tgt=_target,\)\(nam=Name,\)\(URLsepLINKED_CONTENT\)] | Create URL
34 |
35 | HTML Images |
36 | ----------- | ----
37 | [img \(imageTitle,\)**imageURL** \(linkURL\)] | HTML image
38 | [limg \(target=,\)\(lpath=,\)\(wpath=\)\(title=,\)\(alt=,\)**imageName**] | HTML image name, figures size (uses [lipath],[wepath])
39 | [lipath **filePathToImages**] | path for [locimg]
40 | [wepath **webPathToImages**] | path for [locimg]
41 |
42 | HTML Lists |
43 | ---------- | ----
44 | [ul \(istyle=hstyle,\)\(lstyle=hstyle,\)\(wrap=style,\)\(sep=X,\)itemContent\(XitemContent\)] | HTML unordered list
45 | [ol \(type=X,\)\(start=N,\)\(istyle=hstyle,\)\(lstyle=hstyle,\)\(wrap=style,\)\(sep=X,\)itemContent\(XitemContent\)] | HTML ordered list
46 | [iful \(istyle=hstyle,\)\(lstyle=hstyle,\)\(wrap=style,\)\(sep=X,\)itemContent\(XitemContent\)] | HTML unordered list IF > one item
47 | [ifol \(istyle=hstyle,\)\(lstyle=hstyle,\)\(wrap=style,\)\(sep=X,\)itemContent\(XitemContent\)] | HTML ordered list IF > one item
48 | [t \(wrap=style,\)\(sep=X,\)itemContent\(XitemContent\)] | style wrap around item(s)
49 |
50 | HTML Tables |
51 | ----------- | ----
52 | [table \(options\),content] | HTML table \(comma is *not* optional\)
53 | [row \(options\),content] | HTML table row \(comma is *not* optional\)
54 | [header \(options\),content] | HTML table header cell \(comma is *not* optional\)
55 | [cell \(options\),content] | HTML table data cell \(comma is *not* optional\)
56 |
57 | Variables |
58 | --------- | ----
59 | [local **varname** varContent] | local variable definition
60 |
61 | Variables |
62 | --------- | ----
63 | [raw **varname** varContent] | local variable definition
64 | [global **varName** varContent] | global variable definition
65 | [graw **varName** varContent] | global variable definition
66 | [v **varName**] | local/global variable
67 | [vs **varName** varContent] | local variable definition
68 | [gv **varName**] | global variable
69 | [lv **varName**] | local variable
70 | [vinc \(pre=1,\)\(quiet=1,\)**varName**] | increment local(global) variable
71 | [vdec \(pre=1,\)\(quiet=1,\)**varName**] | decrement local(global) variable
72 | [load **varName** **fileName**] | load file into local variable
73 | [gload **varName** **fileName**] | load file into global variable
74 | [save **varName** **fileName**] | save file from local variable
75 | [gsave **varName** **fileName**] | save file from global variable
76 |
77 | Data Lists |
78 | ---------- | ----
79 | [list \(sep=X,\)**listname**,itemContent\(XitemContent\)] | create or overwrite a list
80 | [clearl **listName**] | Discards list content
81 | [lcopy **sourceList** **destinationList**] | copy list to new or existing list
82 | [ltol **listName** content] | convert lines of content to list
83 | [append **listName**,itemContent] | append an item to a list (can create new list)
84 | [lpush **listName**,itemContent] | append an item to a list (can create new list)
85 | [lpop **listName,**\(listIndex\)] | pop an item out of a list at top, or at listIndex
86 | [lset **listName,****listIndex,**itemContent] | Set a list item
87 | [llen **listName**] | returns length of list
88 | [lslice **sliceSpec,****listName,****targetList**] | slice listName to targetList
89 | [lsplit \(sep=^,\)\(num=N,\)**listName**,content] | split content into list
90 | [ljoin **listName**,\(joinTerm\)] | Join a list with joinTerm(s) between elements
91 | [dlist \(fs=styleName,\)\(ls=styleName,\)\(wrap=styleName,\)\(parms=PRE,\)\(inter=INT,\)\(ntl=NTL,\)\(posts=PST,\)listName] | dump a list
92 | [e **listName,****listIndex**] | output item from list of length n (listIndex = 0 to n-1)
93 | [lcc **listOne,****listTwo,****listResult**] | list concatenate
94 | [lsub \(ci=1,\)\(sep=X,\)**listName,**content] | list of form AsepB, A=B in content
95 | [asort \(rev=1,\)**listName**] | ASCII alphabetic sort of list, in place
96 | [aisort \(rev=1,\)**listName**] | ASCII case-insensitive sofr of list, in place
97 | [isort \(rev=1,\)\(sep=X,\)**listName**] | sort by leading integer, sep defaults to ","
98 | [lhsort \(rev=1,\)**listName**] | sort list by leading amateur radio callsign,, any non-alphanumeric sep
99 | [cmap **listName**] | create 1:1 character map
100 | [hmap **listName**] | create 1:1 character map to hex values
101 | [translate \(pre=PRE,\)\(post=POST,\)\(inter=INTER,\)**listName,**content] | translate content using character map formatted list
102 | [postparse content] | pretty-print Python 2.7 code (use black background)
103 | [pythparse content] | pretty-print Python 2.7 code (use black background)
104 | [getc \(var=varName,\)\(embeds=t,\)\(high=lang,\)\(tabsiz=n,\)\(tabchar=X,\)filename] | import c or oc source file as aa_macro
105 |
106 | Data Dictionaries |
107 | ----------------- | ----
108 | [dict \(sep=X,\)\(keysep=Y,\)**dictName,****keyYvalue\(XkeyYvalue\)**] | create/replace dictionary
109 | [dcopy **sourceDictionary,****destinationDictionary**] | copy/replace destination with source
110 | [dkeys **sourceDictionary,****destinationList**] | create a list of keys from source
111 | [dset \(keysep=Y,\)**dictName,****keyYvalue**] | create/replace dictionary item
112 | [d \(sep=X,\)**dictName****Xkey**\(XnotFound\)] | retrieve a dictionary value using key
113 |
114 | General Stack |
115 | ------------- | ----
116 | [push content] | Push an item on to the general stack
117 | [pop] | Pop an item off the top of the general stack
118 | [fetch **itemIndex**] | fetch any item from stack - 0 is top of stack
119 | [flush] | delete stack contents
120 |
121 | Math |
122 | ---- | ----
123 | [int **value**] | integer of number
124 | [round \(digits=decplaces,\)**value**] | rounded value of number
125 | [abs **value**] | absolute value of number
126 | [add \(mode=float,\)**value** **addend**] | add two numbers
127 | [sub \(mode=float,\)**value** **subtrahend**] | subtract two numbers
128 | [mul \(mode=float,\)**value** **multiplier**] | multiply two numbers
129 | [div \(mode=float,\)**value** **divisor**] | divide two numbers
130 | [max **value1** **value2**] | maximum of two numbers
131 | [min **value1** **value2**] | minimum of two numbers
132 | [inc **value**] | add one to value
133 | [dec **value**] | subtract one from value
134 | [random \(seed=none,\(icount=N,\)\)] | generate random from 0.0-1.0
135 | [stage \(mode=float,\)\(digits=N,\)**start** **end** **steps** **step**] | subtract one from value
136 |
137 | Conditional Content |
138 | ------------------- | ----
139 | [even **value** content] | if value is even, then content
140 | [odd **value** content] | if value is odd, then content
141 | [if \(sep=X,\)\(wrap|style=styleName\)**value** **match** content] | if match, then content
142 | [else \(sep=X,\)\(wrap|style=styleName\)**value** **match** content] | if not match, then content
143 | [ne \(sep=X,\)**value,**content] | if value is empty, then content
144 | [eq \(sep=X,\)**value,**content] | if value is not empty, then content
145 | [ifle **value1,****value2 ,**content] | if value1 <= value2, then content
146 | [ifge **value1,****value2 ,**content] | if value1 >= value2, then content
147 |
148 | Text Processing |
149 | --------------- | ----
150 | [slice **sliceSpec,content**] | slice content
151 | [alphalead \(trail=1,\)content] | Return leading alpha characters, or trailing content
152 | [alphanumlead \(trail=1,\)content] | Return leading alphanumeric characters, or trailing content
153 | [splitcount **value**] | Maximum number of splits to perform in next [split]
154 | [split **X,**content\(Xcontent\)] | split for use with [parm]
155 | [locsplit **localName,****X,**content\(Xcontent\)] | split into numbered local variables
156 | [glosplit **localName,****X,**content\(Xcontent\)] | split into numbered global variables
157 | [splash \(pre=,\)\(post=,\)\(inter=,\)\(ntl=,\)\(limit=N,\)\(style=Style,\)\(sep=,,\)content] | splits content, applies style
158 | [parm **value**] | returns results of [split]
159 | [upper content] | convert to uppercase
160 | [lower content] | convert to lowercase
161 | [soundex \(len=N,\)content] | return soundex value of content
162 | [stripe (charset=chars,)content] | strip chars from both ends of line (default = spaces)
163 | [strip content] | strip HTML tags out
164 | [roman **value**] | returns lower case roman numeral
165 | [dtohex (digits=N,)**value**] | decimal to hexadecimal conversion
166 | [dtooct (digits=N,)**value**] | decimal to octal conversion
167 | [dtobin (digits=N,)**value**] | decimal to binary conversion
168 | [htodec (digits=N,)**value**] | hexadecimal to decimal conversion
169 | [otodec (digits=N,)**value**] | octal to decimal conversion
170 | [btodec (digits=N,)**value**] | binary to decimal conversion
171 | [crush ,] | return packed alphanumerics
172 | [collapse content] |
173 | [crop (words=no,)(eol=,)(neol=,)(col=78,)content] |
174 | [wwrap \(eol=X,\)\(wrap=style,\)\(nohtml=1,\)**value,**content] | word wrap content at column value
175 | [len content] | return length of content in characters
176 | [wc content] | return length of content in words
177 | [lc content] | return length of content in lines
178 | [chr **value**] | return ASCII character of code=value
179 | [ord **character**] | return ASCII code value in decimal
180 | [csep **value**] | comma-separate an integer
181 | [fcsep **value**] | comma-separate a floating point number
182 | [dup **value,content**] | duplicate content after evaluation (also see [repeat])
183 | [eval \(style=styleName,\)**value,content**] | duplicate content Nx, eval style Nx if provided
184 | [find \(sep=X,\)**stringXcontent**] | find string in content, sep default = ","
185 | [replace \(sep=X,\(lf=1,\)\)**targetXreplacementXcontent**] | target replaced with replacement in content
186 | [count \(sep=X,\)\(overlaps=yes,\)\(casesens=yes,\)**patternXcontent**] | count incidences
187 | [caps content] | sentence case
188 | [capw content] | word case
189 | [capt content] | title case
190 | [expand **dictName,**content] | dictionary based keyword expansion with leading cap forwarding
191 | [ssort \(rev=1,\)content] | case-sensitive sort of lines
192 | [sisort \(rev=1,\)content] | case-insensitive sort of lines
193 | [issort \(rev=1,\)content] | sort of lines by integer followed by a comma
194 | [hsort \(rev=1,\)content] | sort of lines by amatuer radio callsign followed by non-alphanumeric
195 | [inter **iStr,****L|R,****value,**content] | intersperse iStr every value in content
196 | [rjust **width,****padChar,**content] | right justify
197 | [ljust **width,****padChar,**content] | left justify
198 | [center **width,****padChar,**content] | center (neg width indicates pad both sides)
199 | [th **integer**] | st, nd, rd, th...
200 | [nd **integer**] | 1st, 2nd, 3rd, 4th...
201 | [encrypt \(mode=1,\)\(again=1,\)\(seed=N,\)\(salt=String,\)\(icount=N,\)\(breakat=N,\)content] | (re)Encrypt content
202 | [decrypt \(mode=1,\)\(seed=N,\)\(salt=String,\)\(icount=N,\)content] | Decrypt content
203 | [br \(parms,\)\(content\)] | (content) HTML line break (with parms)
204 |
205 | Miscellanea |
206 | ----------- | ----
207 | [sys **shellCommand**] | invoke an operating system command. Output is captured
208 | [date] | The date of macro() processing (use CGI for live date in HTML)
209 | [ddelta **YYYYMMDD** **YYYYMMDD**] | difference between dates in Y M D
210 | [time \(mode=12|24,\)\(sfx=auto|*,\)\(asfx=,\)\(psfx=,\)] | The time of macro() processing (use CGI for live time in HTML)
211 | [datetime] | The datetime of macro() processing (use CGI for live date in HTML)
212 | [ampm N] | AM or PM from 12 hour number
213 | [term \(astyle=CSSSTYLE,\)CAPSTERM] | if acroclass.py and acrobase.txt present, expand term
214 | [twelve N] | 12 hour number from 24
215 | [month \(mode=long,\)N] | Month name from ordinal
216 | [include **fileName**] | include macro() source file
217 | [embrace **moduleName**] | add, extend, or replace macro() functionality
218 | [repeat **value,**content] | repeat content, evaluating content each time
219 | [comment content] | suppress output. note: non-content operations still process
220 | [back **HEX3|HEX6**] | HTML background text color for HTML 4.01s mode only
221 | [mode **3.2|4.01s**] | set HTML mode
222 | [hlit \(format=1,\)**content**] | places LITERAL content in local variable loc_hlit
223 | [vlit \(format=1,\)**variable-name**] | places LITERAL content in local variable loc_vlit
224 | [slit \(format=1,\)\(wrap=1,\)**style-name**] | places LITERAL content in local variable loc_slit
225 |
226 | Escapes |
227 | ------- | ----
228 | [co] | comma
229 | [sp] | space
230 | [gt] | greater-than
231 | [lt] | less-than
232 | [lb] | left square bracket
233 | [rb] | right square bracket
234 | [ls] | left squiggly bracket
235 | [rs] | right squiggly bracket
236 | [lf|nl] | new line
237 |
238 | Styles |
239 | ------ | ----
240 | [style \(help=helpstring,\)\(help2=helpstring,\)**styleName** **styleContent**] | local style
241 | [gstyle \(help=helpstring,\)\(help2=helpstring,\)**styleName** **styleContent**] | global style
242 | [helps **styleName**] | return help string for local style
243 | [helpg **styleName**] | return help string for global style
244 | [helps2 **styleName**] | return help string 2 for local style
245 | [helpg2 **styleName**] | return help string 2 for global style
246 | [for **styleName**,**X**,**Y**,**Z**] | iterates number to style
247 | [in **styleName**,**listName**] | iterates list to style
248 | [switch \(csep=X,\)\(isep=Y,\)**switchName** **caseYstylename(XcaseYstyleName)**] | switch (works with case)
249 | [case \(sep=X,\)**switchName** **caseXcontent**] | case (works with switch)
250 | [s \(sep=X,\)**stylename**\(styleParameters\)] | invoke style(s), local, if no local, then global
251 | [glos \(sep=X,\)**stylename**\(styleParameters\)] | invoke global style(s)
252 | [locs \(sep=X,\)**stylename**\(styleParameters\)] | invoke local style(s)
253 | [spage] | reset local styles to none
254 | [ghost \(source=global|local,\)**stylename**] | output style without processing it
255 | [fref **lable**] | forward (or backward) reference
256 | [resolve \(hex=1,\)**lable,**content] | resolve reference
257 | [listg \(mode=global] | local,\)**listName,**content| resolve reference
258 |
259 |
260 | ## Alphabetical Order
261 |
262 | _key:_ built-in \(options\) **required** content
263 |
264 | Built-in |
265 | -------- | ----
266 | [a \(tab,\)**URL**\(,linkedContent\)] | HTML link
267 | [abs **value**] | absolute value of number
268 | [add \(mode=float,\)**value** **addend**] | add two numbers
269 | [aisort \(rev=1,\)**listName**] | ASCII case-insensitive sofr of list, in place
270 | [alphalead \(trail=1,\)content] | Return leading alpha characters, or trailing content
271 | [alphanumlead \(trail=1,\)content] | Return leading alphanumeric characters, or trailing content
272 | [ampm N] | AM or PM from 12 hour number
273 | [append **listName**,itemContent] | append an item to a list (can create new list)
274 | [asort \(rev=1,\)**listName**] | ASCII alphabetic sort of list, in place
275 | [b content] | HTML bold
276 | [back **HEX3|HEX6**] | HTML background text color for HTML 4.01s mode only
277 | [bq content] | HTML blockquote
278 | [br \(parms,\)\(content\)] | (content) HTML line break (with parms)
279 | [btodec (digits=N,)**value**] | binary to decimal conversion
280 | [caps content] | sentence case
281 | [capt content] | title case
282 | [capw content] | word case
283 | [case \(sep=X,\)**switchName** **caseXcontent**] | case (works with switch)
284 | [cell \(options\),content] | HTML table data cell \(comma is *not* optional\)
285 | [center **width,****padChar,**content] | center (neg width indicates pad both sides)
286 | [chr **value**] | return ASCII character of code=value
287 | [clearl **listName**] | Discards list content
288 | [cmap **listName**] | create 1:1 character map
289 | [collapse content] |
290 | [color **HEX3|HEX6** content] | HTML text color
291 | [comment content] | suppress output. note: non-content operations still process
292 | [count \(sep=X,\)\(overlaps=yes,\)\(casesens=yes,\)**patternXcontent**] | count incidences
293 | [co] | comma
294 | [crop (words=no,)(eol=,)(neol=,)(col=78,)content] |
295 | [crush ,] | return packed alphanumerics
296 | [csep **value**] | comma-separate an integer
297 | [d \(sep=X,\)**dictName****Xkey**\(XnotFound\)] | retrieve a dictionary value using key
298 | [datetime] | The datetime of macro() processing (use CGI for live date in HTML)
299 | [date] | The date of macro() processing (use CGI for live date in HTML)
300 | [dcopy **sourceDictionary,****destinationDictionary**] | copy/replace destination with source
301 | [ddelta **YYYYMMDD** **YYYYMMDD**] | difference between dates in Y M D
302 | [dec **value**] | subtract one from value
303 | [decrypt \(mode=1,\)\(seed=N,\)\(salt=String,\)\(icount=N,\)content] | Decrypt content
304 | [dict \(sep=X,\)\(keysep=Y,\)**dictName,****keyYvalue\(XkeyYvalue\)**] | create/replace dictionary
305 | [div \(mode=float,\)**value** **divisor**] | divide two numbers
306 | [dkeys **sourceDictionary,****destinationList**] | create a list of keys from source
307 | [dlist \(fs=styleName,\)\(ls=styleName,\)\(wrap=styleName,\)\(parms=PRE,\)\(inter=INT,\)\(ntl=NTL,\)\(posts=PST,\)listName] | dump a list
308 | [dset \(keysep=Y,\)**dictName,****keyYvalue**] | create/replace dictionary item
309 | [dtobin (digits=N,)**value**] | decimal to binary conversion
310 | [dtohex (digits=N,)**value**] | decimal to hexadecimal conversion
311 | [dtooct (digits=N,)**value**] | decimal to octal conversion
312 | [dup **value,content**] | duplicate content after evaluation (also see [repeat])
313 | [e **listName,****listIndex**] | output item from list of length n (listIndex = 0 to n-1)
314 | [else \(sep=X,\)\(wrap|style=styleName\)**value** **match** content] | if not match, then content
315 | [embrace **moduleName**] | add, extend, or replace macro() functionality
316 | [encrypt \(mode=1,\)\(again=1,\)\(seed=N,\)\(salt=String,\)\(icount=N,\)\(breakat=N,\)content] | (re)Encrypt content
317 | [eq \(sep=X,\)**value,**content] | if value is not empty, then content
318 | [eval \(style=styleName,\)**value,content**] | duplicate content Nx, eval style Nx if provided
319 | [even **value** content] | if value is even, then content
320 | [expand **dictName,**content] | dictionary based keyword expansion with leading cap forwarding
321 | [fcsep **value**] | comma-separate a floating point number
322 | [fetch **itemIndex**] | fetch any item from stack - 0 is top of stack
323 | [find \(sep=X,\)**stringXcontent**] | find string in content, sep default = ","
324 | [flush] | delete stack contents
325 | [for **styleName**,**X**,**Y**,**Z**] | iterates number to style
326 | [fref **lable**] | forward (or backward) reference
327 | [getc \(var=varName,\)\(embeds=t,\)\(high=lang,\)\(tabsiz=n,\)\(tabchar=X,\)filename] | import c or oc source file as aa_macro
328 | [ghost \(source=global|local,\)**stylename**] | output style without processing it
329 | [gload **varName** **fileName**] | load file into global variable
330 | [global **varName** varContent] | global variable definition
331 | [glos \(sep=X,\)**stylename**\(styleParameters\)] | invoke global style(s)
332 | [glosplit **localName,****X,**content\(Xcontent\)] | split into numbered global variables
333 | [graw **varName** varContent] | global variable definition
334 | [gsave **varName** **fileName**] | save file from global variable
335 | [gstyle \(help=helpstring,\)\(help2=helpstring,\)**styleName** **styleContent**] | global style
336 | [gt] | greater-than
337 | [gv **varName**] | global variable
338 | [header \(options\),content] | HTML table header cell \(comma is *not* optional\)
339 | [helpg **styleName**] | return help string for global style
340 | [helpg2 **styleName**] | return help string 2 for global style
341 | [helps **styleName**] | return help string for local style
342 | [helps2 **styleName**] | return help string 2 for local style
343 | [hlit \(format=1,\)**content**] | places LITERAL content in local variable loc_hlit
344 | [hmap **listName**] | create 1:1 character map to hex values
345 | [hsort \(rev=1,\)content] | sort of lines by amatuer radio callsign followed by non-alphanumeric
346 | [htodec (digits=N,)**value**] | hexadecimal to decimal conversion
347 | [i content] | HTML italics
348 | [if \(sep=X,\)\(wrap|style=styleName\)**value** **match** content] | if match, then content
349 | [ifge **value1,****value2 ,**content] | if value1 >= value2, then content
350 | [ifle **value1,****value2 ,**content] | if value1 <= value2, then content
351 | [ifol \(istyle=hstyle,\)\(lstyle=hstyle,\)\(wrap=style,\)\(sep=X,\)itemContent\(XitemContent\)] | HTML ordered list IF > one item
352 | [iful \(istyle=hstyle,\)\(lstyle=hstyle,\)\(wrap=style,\)\(sep=X,\)itemContent\(XitemContent\)] | HTML unordered list IF > one item
353 | [img \(imageTitle,\)**imageURL** \(linkURL\)] | HTML image
354 | [in **styleName**,**listName**] | iterates list to style
355 | [inc **value**] | add one to value
356 | [include **fileName**] | include macro() source file
357 | [int **value**] | integer of number
358 | [inter **iStr,****L|R,****value,**content] | intersperse iStr every value in content
359 | [isort \(rev=1,\)\(sep=X,\)**listName**] | sort by leading integer, sep defaults to ","
360 | [issort \(rev=1,\)content] | sort of lines by integer followed by a comma
361 | [lb] | left square bracket
362 | [lc content] | return length of content in lines
363 | [lcc **listOne,****listTwo,****listResult**] | list concatenate
364 | [lcopy **sourceList** **destinationList**] | copy list to new or existing list
365 | [len content] | return length of content in characters
366 | [lf|nl] | new line
367 | [lhsort \(rev=1,\)**listName**] | sort list by leading amateur radio callsign,, any non-alphanumeric sep
368 | [limg \(target=,\)\(lpath=,\)\(wpath=\)\(title=,\)\(alt=,\)**imageName**] | HTML image name, figures size (uses [lipath],[wepath])
369 | [lipath **filePathToImages**] | path for [locimg]
370 | [list \(sep=X,\)**listname**,itemContent\(XitemContent\)] | create or overwrite a list
371 | [listg \(mode=global] | local,\)**listName,**content| resolve reference
372 | [ljoin **listName**,\(joinTerm\)] | Join a list with joinTerm(s) between elements
373 | [ljust **width,****padChar,**content] | left justify
374 | [llen **listName**] | returns length of list
375 | [load **varName** **fileName**] | load file into local variable
376 | [local **varname** varContent] | local variable definition
377 | [locs \(sep=X,\)**stylename**\(styleParameters\)] | invoke local style(s)
378 | [locsplit **localName,****X,**content\(Xcontent\)] | split into numbered local variables
379 | [lower content] | convert to lowercase
380 | [lpop **listName,**\(listIndex\)] | pop an item out of a list at top, or at listIndex
381 | [lpush **listName**,itemContent] | append an item to a list (can create new list)
382 | [lset **listName,****listIndex,**itemContent] | Set a list item
383 | [lslice **sliceSpec,****listName,****targetList**] | slice listName to targetList
384 | [lsplit \(sep=^,\)\(num=N,\)**listName**,content] | split content into list
385 | [lsub \(ci=1,\)\(sep=X,\)**listName,**content] | list of form AsepB, A=B in content
386 | [ls] | left squiggly bracket
387 | [ltol **listName** content] | convert lines of content to list
388 | [lt] | less-than
389 | [lv **varName**] | local variable
390 | [max **value1** **value2**] | maximum of two numbers
391 | [min **value1** **value2**] | minimum of two numbers
392 | [mode **3.2|4.01s**] | set HTML mode
393 | [month \(mode=long,\)N] | Month name from ordinal
394 | [mul \(mode=float,\)**value** **multiplier**] | multiply two numbers
395 | [nd **integer**] | 1st, 2nd, 3rd, 4th...
396 | [ne \(sep=X,\)**value,**content] | if value is empty, then content
397 | [odd **value** content] | if value is odd, then content
398 | [ol \(type=X,\)\(start=N,\)\(istyle=hstyle,\)\(lstyle=hstyle,\)\(wrap=style,\)\(sep=X,\)itemContent\(XitemContent\)] | HTML ordered list
399 | [ord **character**] | return ASCII code value in decimal
400 | [otodec (digits=N,)**value**] | octal to decimal conversion
401 | [p content] | HTML paragraph
402 | [parm **value**] | returns results of [split]
403 | [pop] | Pop an item off the top of the general stack
404 | [postparse content] | pretty-print Python 2.7 code (use black background)
405 | [push content] | Push an item on to the general stack
406 | [pythparse content] | pretty-print Python 2.7 code (use black background)
407 | [random \(seed=none,\(icount=N,\)\)] | generate random from 0.0-1.0
408 | [raw **varname** varContent] | local variable definition
409 | [rb] | right square bracket
410 | [repeat **value,**content] | repeat content, evaluating content each time
411 | [replace \(sep=X,\(lf=1,\)\)**targetXreplacementXcontent**] | target replaced with replacement in content
412 | [resolve \(hex=1,\)**lable,**content] | resolve reference
413 | [rjust **width,****padChar,**content] | right justify
414 | [roman **value**] | returns lower case roman numeral
415 | [round \(digits=decplaces,\)**value**] | rounded value of number
416 | [row \(options\),content] | HTML table row \(comma is *not* optional\)
417 | [rs] | right squiggly bracket
418 | [s \(sep=X,\)**stylename**\(styleParameters\)] | invoke style(s), local, if no local, then global
419 | [save **varName** **fileName**] | save file from local variable
420 | [sisort \(rev=1,\)content] | case-insensitive sort of lines
421 | [slice **sliceSpec,content**] | slice content
422 | [slit \(format=1,\)\(wrap=1,\)**style-name**] | places LITERAL content in local variable loc_slit
423 | [soundex \(len=N,\)content] | return soundex value of content
424 | [spage] | reset local styles to none
425 | [splash \(pre=,\)\(post=,\)\(inter=,\)\(ntl=,\)\(limit=N,\)\(style=Style,\)\(sep=,,\)content] | splits content, applies style
426 | [split **X,**content\(Xcontent\)] | split for use with [parm]
427 | [splitcount **value**] | Maximum number of splits to perform in next [split]
428 | [sp] | space
429 | [ssort \(rev=1,\)content] | case-sensitive sort of lines
430 | [stage \(mode=float,\)\(digits=N,\)**start** **end** **steps** **step**] | subtract one from value
431 | [strip content] | strip HTML tags out
432 | [stripe (charset=chars,)content] | strip chars from both ends of line (default = spaces)
433 | [style \(help=helpstring,\)\(help2=helpstring,\)**styleName** **styleContent**] | local style
434 | [sub \(mode=float,\)**value** **subtrahend**] | subtract two numbers
435 | [switch \(csep=X,\)\(isep=Y,\)**switchName** **caseYstylename(XcaseYstyleName)**] | switch (works with case)
436 | [sys **shellCommand**] | invoke an operating system command. Output is captured
437 | [t \(wrap=style,\)\(sep=X,\)itemContent\(XitemContent\)] | style wrap around item(s)
438 | [table \(options\),content] | HTML table \(comma is *not* optional\)
439 | [term \(astyle=CSSSTYLE,\)CAPSTERM] | if acroclass.py and acrobase.txt present, expand term
440 | [th **integer**] | st, nd, rd, th...
441 | [time \(mode=12|24,\)\(sfx=auto|*,\)\(asfx=,\)\(psfx=,\)] | The time of macro() processing (use CGI for live time in HTML)
442 | [translate \(pre=PRE,\)\(post=POST,\)\(inter=INTER,\)**listName,**content] | translate content using character map formatted list
443 | [twelve N] | 12 hour number from 24
444 | [u content] | HTML underline
445 | [ul \(istyle=hstyle,\)\(lstyle=hstyle,\)\(wrap=style,\)\(sep=X,\)itemContent\(XitemContent\)] | HTML unordered list
446 | [upper content] | convert to uppercase
447 | [url \(sep=|,\)\(css=CSS,\)\(tgt=_target,\)\(nam=Name,\)\(URLsepLINKED_CONTENT\)] | Create URL
448 | [urlencode **content**] | URL encoding
449 | [v **varName**] | local/global variable
450 | [vdec \(pre=1,\)\(quiet=1,\)**varName**] | decrement local(global) variable
451 | [vinc \(pre=1,\)\(quiet=1,\)**varName**] | increment local(global) variable
452 | [vlit \(format=1,\)**variable-name**] | places LITERAL content in local variable loc_vlit
453 | [vs **varName** varContent] | local variable definition
454 | [wc content] | return length of content in words
455 | [wepath **webPathToImages**] | path for [locimg]
456 | [wwrap \(eol=X,\)\(wrap=style,\)\(nohtml=1,\)**value,**content] | word wrap content at column value
457 |
458 |
459 |
--------------------------------------------------------------------------------
/quickref.txt:
--------------------------------------------------------------------------------
1 | [comment
2 | The task here is to create two tables of built-ins, the first being
3 | grouped by function, and the second in alphabetical order.
4 |
5 | "bil" is a data list. The first append creates it; the following ones
6 | add more items. As it is a list, and not a dictionary, it has a defined
7 | ordering which is used here to group the various types of built-ins
8 | together. Each append describes one built-in.
9 |
10 | Once the list is created, it is displayed, in order. The style used for
11 | this parses out the "~" separated component in the list item as a heading
12 | title; when it exists, it creates a header line.
13 |
14 | Then the list is sorted, and redisplayed, this time using a style that is
15 | mostly similar, but does not act upon the "~" separated information.
16 |
17 | The styles controlling how this list are presented are in the qr_html.txt
18 | and qr_markdown.txt files. These provide a means to generate HTML or
19 | markdown, respectively. Generation of output files is performed as follows:
20 |
21 | HTML: aagen -i qr_html.txt -f quickref.html quickref.txt
22 | Markdown: aagen -i qr_markdown.txt -f quickref.md quickref.txt
23 | ]
24 | [append bil,p {c}| HTML paragraph~HTML Text Styling]
25 | [append bil,bq {c}| HTML blockquote]
26 | [append bil,b {c}| HTML bold]
27 | [append bil,i {c}| HTML italics]
28 | [append bil,u {c}| HTML underline]
29 | [append bil,color {r HEX3{vb}HEX6} {c}| HTML text color]
30 | [append bil,a {o tab{co}}{r URL}{o {co}linkedContent}| HTML link~HTML Linking]
31 | [append bil,urlencode {r content}| URL encoding]
32 | [append bil,url {o sep={vb}{co}}{o css=CSS{co}}{o tgt=_target{co}}{o nam=Name{co}}{o URLsepLINKED_CONTENT}|Create URL]
33 | [append bil,img {o imageTitle{co}}{r imageURL} {o linkURL}| HTML image~HTML Images]
34 | [append bil,limg {o target={co}}{o lpath={co}}{o wpath=}{o title={co}}{o alt={co}}{r imageName}| HTML image name, figures size (uses {lb}lipath{rb},{lb}wepath{rb})]
35 | [append bil,lipath {r filePathToImages}| path for {lb}locimg{rb}]
36 | [append bil,wepath {r webPathToImages}| path for {lb}locimg{rb}]
37 | [append bil,ul {o istyle=hstyle{co}}{o lstyle=hstyle{co}}{o wrap=style{co}}{o sep=X{co}}{cc itemContent{o XitemContent}}| HTML unordered list~HTML Lists]
38 | [append bil,ol {o type=X{co}}{o start=N{co}}{o istyle=hstyle{co}}{o lstyle=hstyle{co}}{o wrap=style{co}}{o sep=X{co}}{cc itemContent{o XitemContent}}| HTML ordered list]
39 | [append bil,iful {o istyle=hstyle{co}}{o lstyle=hstyle{co}}{o wrap=style{co}}{o sep=X{co}}{cc itemContent{o XitemContent}}| HTML unordered list IF > one item]
40 | [append bil,ifol {o istyle=hstyle{co}}{o lstyle=hstyle{co}}{o wrap=style{co}}{o sep=X{co}}{cc itemContent{o XitemContent}}| HTML ordered list IF > one item]
41 | [append bil,t {o wrap=style{co}}{o sep=X{co}}{cc itemContent{o XitemContent}}| style wrap around item(s)]
42 | [append bil,table {o options}{co}{c}| HTML table \(comma is *not* optional\)~HTML Tables]
43 | [append bil,row {o options}{co}{c}| HTML table row \(comma is *not* optional\)]
44 | [append bil,header {o options}{co}{c}| HTML table header cell \(comma is *not* optional\)]
45 | [append bil,cell {o options}{co}{c}| HTML table data cell \(comma is *not* optional\)]
46 |
47 | [append bil,local {r varname} {cc varContent}| local variable definition~Variables]
48 | [append bil,raw {r varname} {cc varContent}| local variable definition~Variables]
49 | [append bil,global {r varName} {cc varContent}| global variable definition]
50 | [append bil,graw {r varName} {cc varContent}| global variable definition]
51 | [append bil,v {r varName}| local/global variable]
52 | [append bil,vs {r varName} {cc varContent}| local variable definition]
53 | [append bil,gv {r varName}| global variable]
54 | [append bil,lv {r varName}| local variable]
55 | [append bil,vinc {o pre=1{co}}{o quiet=1{co}}{r varName}| increment local(global) variable]
56 | [append bil,vdec {o pre=1{co}}{o quiet=1{co}}{r varName}| decrement local(global) variable]
57 | [append bil,load {r varName} {r fileName}| load file into local variable]
58 | [append bil,gload {r varName} {r fileName}| load file into global variable]
59 | [append bil,save {r varName} {r fileName}| save file from local variable]
60 | [append bil,gsave {r varName} {r fileName}| save file from global variable]
61 |
62 | [append bil,list {o sep=X{co}}{r listname}{co}{cc itemContent}{o XitemContent}| create or overwrite a list~Data Lists]
63 | [append bil,clearl {r listName}| Discards list content]
64 | [append bil,lcopy {r sourceList} {r destinationList}| copy list to new or existing list]
65 | [append bil,ltol {r listName} {c}| convert lines of content to list]
66 | [append bil,append {r listName}{co}{cc itemContent}| append an item to a list (can create new list)]
67 | [append bil,lpush {r listName}{co}{cc itemContent}| append an item to a list (can create new list)]
68 | [append bil,lpop {r listName{co}}{o listIndex}| pop an item out of a list at top, or at listIndex]
69 | [append bil,lset {r listName{co}}{r listIndex{co}}{cc itemContent}| Set a list item]
70 | [append bil,llen {r listName}| returns length of list]
71 | [append bil,lslice {r sliceSpec{co}}{r listName{co}}{r targetList}| slice listName to targetList]
72 | [append bil,lsplit {o sep=^{co}}{o num=N{co}}{r listName}{co}{c}| split content into list]
73 | [append bil,ljoin {r listName}{co}{o joinTerm}| Join a list with joinTerm(s) between elements]
74 | [append bil,dlist {o fs=styleName{co}}{o ls=styleName{co}}{o wrap=styleName{co}}{o parms=PRE{co}}{o inter=INT{co}}{o ntl=NTL{co}}{o posts=PST{co}}listName| dump a list]
75 | [append bil,e {r listName{co}}{r listIndex}| output item from list of length n (listIndex = 0 to n-1)]
76 | [append bil,lcc {r listOne{co}}{r listTwo{co}}{r listResult}| list concatenate]
77 |
78 | [append bil,lsub {o ci=1{co}}{o sep=X{co}}{r listName{co}}{c}| list of form AsepB, A=B in content]
79 | [append bil,asort {o rev=1{co}}{r listName}| ASCII alphabetic sort of list{co} in place]
80 | [append bil,aisort {o rev=1{co}}{r listName}| ASCII case-insensitive sofr of list{co} in place]
81 | [append bil,isort {o rev=1{co}}{o sep=X{co}}{r listName}| sort by leading integer{co} sep defaults to {q}{co}{q}]
82 | [append bil,lhsort {o rev=1{co}}{r listName}| sort list by leading amateur radio callsign{co}, any non-alphanumeric sep]
83 | [append bil,cmap {r listName}| create 1:1 character map]
84 | [append bil,hmap {r listName}| create 1:1 character map to hex values]
85 | [append bil,translate {o pre=PRE{co}}{o post=POST{co}}{o inter=INTER{co}}{r listName{co}}{c}| translate content using character map formatted list]
86 | [append bil,postparse {c}| pretty-print Python 2.7 code (use black background)]
87 | [append bil,pythparse {c}| pretty-print Python 2.7 code (use black background)]
88 | [append bil,getc {o var=varName{co}}{o embeds=t{co}}{o high=lang{co}}{o tabsiz=n{co}}{o tabchar=X{co}}filename| import c or oc source file as aa_macro]
89 |
90 | [append bil,dict {o sep=X{co}}{o keysep=Y{co}}{r dictName{co}}{r keyYvalue{o XkeyYvalue}}| create/replace dictionary~Data Dictionaries]
91 | [append bil,dcopy {r sourceDictionary{co}}{r destinationDictionary}| copy/replace destination with source]
92 | [append bil,dkeys {r sourceDictionary{co}}{r destinationList}| create a [b list] of keys from source]
93 | [append bil,dset {o keysep=Y{co}}{r dictName{co}}{r keyYvalue}| create/replace dictionary item]
94 | [append bil,d {o sep=X{co}}{r dictName}{r Xkey}{o XnotFound}| retrieve a dictionary value using key]
95 |
96 | [append bil,push {c}| Push an item on to the general stack~General Stack]
97 | [append bil,pop| Pop an item off the top of the general stack]
98 | [append bil,fetch {r itemIndex}| fetch any item from stack - 0 is top of stack]
99 | [append bil,flush| delete stack contents]
100 |
101 | [append bil,int {r value}| integer of number~Math]
102 | [append bil,round {o digits=decplaces{co}}{r value}| rounded value of number]
103 | [append bil,abs {r value}| absolute value of number]
104 | [append bil,add {o mode=float{co}}{r value} {r addend}| add two numbers]
105 | [append bil,sub {o mode=float{co}}{r value} {r subtrahend}| subtract two numbers]
106 | [append bil,mul {o mode=float{co}}{r value} {r multiplier}| multiply two numbers]
107 | [append bil,div {o mode=float{co}}{r value} {r divisor}| divide two numbers]
108 | [append bil,max {r value1} {r value2}| maximum of two numbers]
109 | [append bil,min {r value1} {r value2}| minimum of two numbers]
110 | [append bil,inc {r value}| add one to value]
111 | [append bil,dec {r value}| subtract one from value]
112 | [append bil,random {o seed=none{co}{o icount=N{co}}}| generate random from 0.0-1.0]
113 | [append bil,stage {o mode=float{co}}{o digits=N{co}}{r start} {r end} {r steps} {r step}| subtract one from value]
114 |
115 | [append bil,even {r value} {c}| if value is even{co} then content~Conditional Content]
116 | [append bil,odd {r value} {c}| if value is odd{co} then content]
117 | [append bil,if {o sep=X{co}}{o wrap{vb}style=styleName}{r value} {r match} {c}| if match{co} then content]
118 | [append bil,else {o sep=X{co}}{o wrap{vb}style=styleName}{r value} {r match} {c}| if [b not] match{co} then content]
119 | [append bil,ne {o sep=X{co}}{r value{co}}{c}| if value is empty{co} then content]
120 | [append bil,eq {o sep=X{co}}{r value{co}}{c}| if value is [b not] empty{co} then content]
121 | [append bil,ifle {r value1{co}}{r value2 {co}}{c}| if value1 <= value2{co} then content]
122 | [append bil,ifge {r value1{co}}{r value2 {co}}{c}| if value1 >= value2{co} then content]
123 |
124 | [append bil,slice {r sliceSpec{co}{c}}| slice content~Text Processing]
125 | [append bil,alphalead {o trail=1,}{c}|Return leading alpha characters{co} or trailing content]
126 | [append bil,alphanumlead {o trail=1,}{c}|Return leading alphanumeric characters{co} or trailing content]
127 | [append bil,splitcount {r value}| Maximum number of splits to perform in next {lb}split{rb}]
128 | [append bil,split {r X{co}}{c}{o Xcontent}| split for use with {lb}parm{rb}]
129 | [append bil,locsplit {r localName{co}}{r X{co}}{c}{o Xcontent}| split into numbered local variables]
130 | [append bil,glosplit {r localName{co}}{r X{co}}{c}{o Xcontent}| split into numbered global variables]
131 | [append bil,splash {o pre={co}}{o post={co}}{o inter={co}}{o ntl={co}}{o limit=N{co}}{o style=Style{co}}{o sep={co}{co}}{c}| splits content, applies style]
132 | [append bil,parm {r value}| returns results of {lb}split{rb}]
133 | [append bil,upper {c}| convert to uppercase]
134 | [append bil,lower {c}| convert to lowercase]
135 | [append bil,soundex {o len=N{co}}{c}| return soundex value of content]
136 | [append bil,stripe (charset=chars,){c}| strip chars from both ends of line (default = spaces)]
137 | [append bil,strip {c}| strip HTML tags out]
138 | [append bil,roman {r value}| returns lower case roman numeral]
139 | [append bil,dtohex (digits=N{co}){r value}| decimal to hexadecimal conversion]
140 | [append bil,dtooct (digits=N{co}){r value}| decimal to octal conversion]
141 | [append bil,dtobin (digits=N{co}){r value}| decimal to binary conversion]
142 | [append bil,htodec (digits=N{co}){r value}| hexadecimal to decimal conversion]
143 | [append bil,otodec (digits=N{co}){r value}| octal to decimal conversion]
144 | [append bil,btodec (digits=N{co}){r value}| binary to decimal conversion]
145 | [append bil,crush {co}| return packed alphanumerics]
146 | [append bil,collapse {c}]
147 | [append bil,crop (words=no{co})(eol={co})(neol={co})(col=78{co}){c}]
148 | [append bil,wwrap {o eol=X{co}}{o wrap=style{co}}{o nohtml=1{co}}{r value{co}}{c}| word wrap content at column value]
149 | [append bil,len {c}| return length of content in characters]
150 | [append bil,wc {c}| return length of content in words]
151 | [append bil,lc {c}| return length of content in lines]
152 | [append bil,chr {r value}| return ASCII character of code=value]
153 | [append bil,ord {r character}| return ASCII code value in decimal]
154 | [append bil,csep {r value}| comma-separate an integer]
155 | [append bil,fcsep {r value}| comma-separate a floating point number]
156 | [append bil,dup {r value{co}{c}}| duplicate content [i after] evaluation (also see {lb}repeat{rb})]
157 | [append bil,eval {o style=styleName{co}}{r value{co}{c}}| duplicate content Nx{co} eval style Nx if provided]
158 | [append bil,find {o sep=X{co}}{r stringXcontent}| find string in content{co} sep default = {q}{co}{q}]
159 | [append bil,replace {o sep=X{co}{o lf=1{co}}}{r targetXreplacementXcontent}| target replaced with replacement in content]
160 | [append bil,count {o sep=X{co}}{o overlaps=yes{co}}{o casesens=yes{co}}{r patternXcontent}| count incidences]
161 | [append bil,caps {c}| sentence case]
162 | [append bil,capw {c}| word case]
163 | [append bil,capt {c}| title case]
164 | [append bil,expand {r dictName{co}}{c}| dictionary based keyword expansion with leading cap forwarding]
165 | [append scase, {r listName{co}}{c}| special case words in content using casing in list]
166 | [append bil,ssort {o rev=1{co}}{c}| case-sensitive sort of lines]
167 | [append bil,sisort {o rev=1{co}}{c}| case-insensitive sort of lines]
168 | [append bil,issort {o rev=1{co}}{c}| sort of lines by integer followed by a comma]
169 | [append bil,hsort {o rev=1{co}}{c}| sort of lines by amatuer radio callsign followed by non-alphanumeric]
170 | [append bil,inter {r iStr{co}}{r L{vb}R{co}}{r value{co}}{c}| intersperse iStr every value in content]
171 | [append bil,rjust {r width{co}}{r padChar{co}}{c}| right justify]
172 | [append bil,ljust {r width{co}}{r padChar{co}}{c}| left justify]
173 | [append bil,center {r width{co}}{r padChar{co}}{c}| center (neg width indicates pad both sides)]
174 | [append bil,th {r integer}| st, nd, rd, th...]
175 | [append bil,nd {r integer}| 1st, 2nd, 3rd, 4th...]
176 | [append bil,encrypt {o mode=1{co}}{o again=1{co}}{o seed=N{co}}{o salt=String{co}}{o icount=N{co}}{o breakat=N{co}}{c}| (re)Encrypt content]
177 | [append bil,decrypt {o mode=1{co}}{o seed=N{co}}{o salt=String{co}}{o icount=N{co}}{c}| Decrypt content]
178 | [append bil,br {o parms{co}}{o content}| (content) HTML line break (with parms)]
179 |
180 | [append bil,sys {r shellCommand}| invoke an operating system command. Output is captured~Miscellanea]
181 | [append bil,date| The date of macro() processing (use CGI for live date in HTML)]
182 | [append bil,ddelta {r YYYYMMDD} {r YYYYMMDD}| difference between dates in Y M D]
183 | [append bil,time {o mode=12{vb}24{co}}{o sfx=auto{vb}*{co}}{o asfx={co}}{o psfx={co}}| The time of macro() processing (use CGI for live time in HTML)]
184 | [append bil,datetime| The datetime of macro() processing (use CGI for live date in HTML)]
185 | [append bil,ampm N| AM or PM from 12 hour number]
186 | [append bil,term {o astyle=CSSSTYLE[co]}CAPSTERM| if acroclass.py and acrobase.txt present, expand term]
187 | [append bil,twelve N| 12 hour number from 24]
188 | [append bil,month {o mode=long,}N| Month name from ordinal]
189 | [append bil,include {r fileName}| include macro() source file]
190 | [append bil,embrace {r moduleName}| add{co} extend{co} or replace macro() functionality]
191 | [append bil,repeat {r value{co}}{c}| repeat content{co} evaluating content [i each time]]
192 | [append bil,comment {c}| suppress output. [i note: non-content operations still process]]
193 | [append bil,back {r HEX3{vb}HEX6}| HTML background text color for HTML 4.01s mode [i only]]
194 | [append bil,mode {r 3.2{vb}4.01s}| set HTML mode]
195 | [append bil,hlit {o format=1[co]}{r content}| places LITERAL content in local variable loc_hlit]
196 | [append bil,vlit {o format=1[co]}{r variable-name}| places LITERAL content in local variable loc_vlit]
197 | [append bil,slit {o format=1[co]}{o wrap=1[co]}{r style-name}| places LITERAL content in local variable loc_slit]
198 |
199 | [append bil,co| comma~Escapes]
200 | [append bil,sp| space]
201 | [append bil,gt| greater-than]
202 | [append bil,lt| less-than]
203 | [append bil,lb| left square bracket]
204 | [append bil,rb| right square bracket]
205 | [append bil,ls| left squiggly bracket]
206 | [append bil,rs| right squiggly bracket]
207 | [append bil,lf{vb}nl| new line]
208 |
209 | [append bil,style {o help=helpstring{co}}{o help2=helpstring{co}}{r styleName} {r styleContent}| local style~Styles]
210 | [append bil,gstyle {o help=helpstring{co}}{o help2=helpstring{co}}{r styleName} {r styleContent}| global style]
211 | [append bil,helps {r styleName}| return help string for local style]
212 | [append bil,helpg {r styleName}| return help string for global style]
213 | [append bil,helps2 {r styleName}| return help string 2 for local style]
214 | [append bil,helpg2 {r styleName}| return help string 2 for global style]
215 | [append bil,for {r styleName}{co}{r X}{co}{r Y}{co}{r Z}| iterates number to style]
216 | [append bil,in {r styleName}{co}{r listName}| iterates list to style]
217 | [append bil,switch {o csep=X{co}}{o isep=Y{co}}{r switchName} {r caseYstylename(XcaseYstyleName)}| switch (works with case)]
218 | [append bil,case {o sep=X{co}}{r switchName} {r caseXcontent}| case (works with switch)]
219 | [append bil,s {o sep=X{co}}{r stylename}{o styleParameters}| invoke style(s){co} local{co} if no local{co} then global]
220 | [append bil,glos {o sep=X{co}}{r stylename}{o styleParameters}| invoke global style(s)]
221 | [append bil,locs {o sep=X{co}}{r stylename}{o styleParameters}| invoke local style(s)]
222 | [append bil,spage| reset local styles to [i none]]
223 | [append bil,ghost {o source=global{vb}local{co}}{r stylename}| output style without processing it]
224 | [append bil,fref {r lable}| forward (or backward) reference]
225 | [append bil,resolve {o hex=1{co}}{r lable{co}}{c}| resolve reference]
226 | [append bil,listg {o mode=global|local{co}}{r listName{co}}{c}| resolve reference]
227 |
228 | {# The following generates the page}
229 | {# --------------------------------}
230 |
231 | {page
232 | {h1 Macro() BETA Quick Reference}
233 | {h2 Functional Groupings}
234 |
235 | {p
236 | {i key:} built-in {o options} {r required} {cc content}
237 | }
238 |
239 | {table
240 | [dlist style=bistyle,bil]
241 | }
242 |
243 | {h2 Alphabetical Order}
244 |
245 | {p
246 | {i key:} built-in {o options} {r required} {cc content}
247 | }
248 |
249 | [asort bil]
250 | {table2
251 | [dlist style=bxstyle,bil]
252 | }
253 | }
254 |
--------------------------------------------------------------------------------
/tease.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fyngyrz/aa_macro/34f09ebbefd1c02fd31366dd17de2f7c0f6f877f/tease.png
--------------------------------------------------------------------------------
/test.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fyngyrz/aa_macro/34f09ebbefd1c02fd31366dd17de2f7c0f6f877f/test.gif
--------------------------------------------------------------------------------
/test.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fyngyrz/aa_macro/34f09ebbefd1c02fd31366dd17de2f7c0f6f877f/test.jpg
--------------------------------------------------------------------------------
/test.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fyngyrz/aa_macro/34f09ebbefd1c02fd31366dd17de2f7c0f6f877f/test.png
--------------------------------------------------------------------------------
/test_aa_macro.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python
2 |
3 | import unittest
4 | import codecs
5 | from aa_macro import *
6 | import difflib
7 | import sys
8 | from aa_ansiicolor import *
9 |
10 | c = htmlAnsii()
11 |
12 | def nocrlf(s):
13 | while len(s) > 0 and (s[-1] == '\n' or s[-1] == '\r'):
14 | s = s[:-1]
15 | return s
16 |
17 | def diffme(fna,fnb,barlen):
18 | global c
19 | bar = '-' * barlen
20 | bar = c.c(bar,'blue')
21 | fh = open(fna)
22 | fa = fh.read().splitlines(1)
23 | fh.close()
24 |
25 | fh = open(fnb)
26 | fb = fh.read().splitlines(1)
27 | fh.close()
28 |
29 | d = difflib.Differ()
30 |
31 | result = list(d.compare(fa, fb))
32 |
33 | print bar
34 | missingcolor = 'red'
35 | addedcolor = 'white'
36 | quotecolor = 'yellow'
37 | stringcolor = 'aqua'
38 | for line in result:
39 | if line[0] != ' ':
40 | line = nocrlf(line) # terminating cr/lf removed
41 | if line[0] == '-':
42 | out = c.c('-',missingcolor) + c.c(' "',quotecolor) + c.c(line[2:],'aqua')+c.c('"',quotecolor)
43 | elif line[0] == '+':
44 | out = c.c('+',addedcolor) + c.c(' "',quotecolor) + c.c(line[2:],'aqua')+c.c('"',quotecolor)
45 | out += '\n'
46 | sys.stdout.write(out)
47 | print bar
48 | print c.c('End of differences','green')
49 |
50 | class TestAAMacro(unittest.TestCase):
51 |
52 | def test_aa_macro(self):
53 | """
54 | Test aa_macro.py functionality
55 | """
56 | global c
57 | bar = '-' * 40
58 | print c.c(bar,'blue')
59 | expect = 'expected.html'
60 | badout = 'badoutput.html'
61 |
62 | # read unicode sample:
63 | try:
64 | fh = codecs.open('unisample.txt', encoding='utf-8')
65 | testBlock = fh.read()
66 | fh.close()
67 | st = str(type(testBlock))
68 | if st != "": print 'failure to convert file to unicode'
69 | except:
70 | print 'failed to read unicode sample'
71 |
72 | # process unicode to ASCII:
73 | try:
74 | umod = macro(ucin=True)
75 | s = umod.unido(testBlock)
76 | st = str(type(s))
77 | if st != "": print 'failure to convert unicode to ASCII'
78 | except:
79 | print 'failed to process unicode to ASCII'
80 |
81 | # process unicode to unicode:
82 | try:
83 | umod = macro(ucin=True,ucout=True)
84 | umod.unido(testBlock)
85 | s = umod.uniget()
86 | st = str(type(s))
87 | if st != "": print 'failure to process unicode to unicode'
88 | except:
89 | print 'failed to process unicode to unicode'
90 |
91 | rebuild = 1
92 | fh = open('mactest.txt')
93 | testBlock = fh.read()
94 | fh.close()
95 | mod = macro(debug=True)
96 | output = mod.do(testBlock)
97 | dtrace = mod.getdebug()
98 | fh = open("aam_dtrace.txt",'w')
99 | fh.write(dtrace)
100 | fh.close()
101 |
102 | mod = macro(noembrace=True)
103 | output2 = mod.do('[embrace embrace-example.py]\n')
104 | output = output + output2
105 |
106 | mod = macro(noinclude=True)
107 | output3 = mod.do('[include aagen-example.txt]\n')
108 | output = output + output3
109 |
110 | mod = macro(noshell=True)
111 | output4 = mod.do('[sys echo shell test]\n[gload othervar forvariable.txt]\n[load myvar forvariable.txt]\n')
112 | output = output + output4
113 |
114 | mod = macro(xlimit=5)
115 | output5 = mod.do('[style dome [b]]\n[for dome,0,10,1]\n[repeat 10 x-]\n[dup 10,y-]\n[eval 10,z-]')
116 | output = output + output5
117 |
118 | # for, repeat, dup, eval
119 | mod = macro(dlimit=1)
120 | output6 = mod.do('[style dome2 [b]][style dome [for dome2,0,2,1]]\n[for dome,0,2,1]\n')
121 | output = output + output6
122 |
123 | mod = macro(dlimit=1)
124 | output7 = mod.do('[repeat 2 [repeat 2 aB]]\n')
125 | output = output + output7
126 |
127 | mod = macro(dlimit=1)
128 | output8 = mod.do('[repeat 2 [dup 2,[dup 2,aB]]]\n')
129 | output = output + output8
130 |
131 | mod = macro(dlimit=1)
132 | output9 = mod.do('[repeat 2 [eval 2,[eval 2,oX]]]\n')
133 | output = output + output9
134 |
135 | if rebuild == 1:
136 | fileName = 'testresult.html'
137 | try:
138 | fileHandle = open(fileName,'w')
139 | except:
140 | print 'Unable to open "%s"' % fileName
141 | else:
142 | try:
143 | fileHandle.write(output)
144 | except:
145 | print 'Unable to write output to "%s"' % fileName
146 | try:
147 | fileHandle.close()
148 | except:
149 | print 'Unable to close "%s"' % fileName
150 |
151 | fh = open(expect)
152 | expected = fh.read()
153 | fh.close()
154 | if expected == output:
155 | result = True
156 | else:
157 | print c.c('ERROR: expected != output','red')
158 | s = 'Comparing %s with %s:' % (expect,badout)
159 | bl = len(s)
160 | print c.c(s,'yellow')
161 | result = False
162 | ok = True
163 | try:
164 | fh = open(badout,'w')
165 | fh.write(output)
166 | except:
167 | ok = False
168 | print '>>> Could not write "%s". Do permissions need adjustment?' % (badout,)
169 | try:
170 | fh.close()
171 | except:
172 | ok = False
173 | if ok == True:
174 | diffme(expect,badout,bl)
175 | try:
176 | self.assertEqual(True,result,'expected != output\nCompare expected.html with badoutput.html')
177 | except:
178 | pass
179 |
180 | if __name__ == '__main__':
181 | unittest.main()
182 |
--------------------------------------------------------------------------------
/testing.README.md:
--------------------------------------------------------------------------------
1 | Testing
2 | -------
3 |
4 | Testing requires the presence of the following files:
5 |
6 | ```
7 | aa_ansiicolor.py
8 | expected.html
9 | mactest.txt
10 | test.gif
11 | test.jpg
12 | test.png
13 | test_aa_macro.py
14 | ```
15 |
16 | Testing requires that the directory with the test files be the
17 | current directory.
18 |
19 | Testing requires that the user executing the test posses
20 | write permission for the directory within which the test
21 | is performed.
22 |
23 | All tests are in [test_aa_macro.py](test_aa_macro.py), and can be run with:
24 |
25 | python test_aa_macro.py
26 |
27 | On success, this will have a zero exit status, and the output will look like the following:
28 |
29 | .
30 | ----------------------------------------------------------------------
31 | Ran 1 test in 0.000s
32 |
33 | OK
34 |
35 | On failure, error messages will be presented, and a list of the differences
36 | between what was expected from the test, and the output of the test.
37 |
38 | Lines that begin with a \- indicate that this information was expected, but was
39 | missing in the output.
40 |
41 | Lines that begin with a \+ indicate that this information was not expected,
42 | but was present in the output.
43 |
--------------------------------------------------------------------------------
/textmate-syntax.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fyngyrz/aa_macro/34f09ebbefd1c02fd31366dd17de2f7c0f6f877f/textmate-syntax.png
--------------------------------------------------------------------------------
/textmate-syntax.txt:
--------------------------------------------------------------------------------
1 | { scopeName = 'source.aa_macro';
2 | fileTypes = ( );
3 | patterns = (
4 | { name = 'keyword.body.aa_macro';
5 | begin = '\[';
6 | end = '[\s|\]]';
7 | patterns = (
8 | { name = 'constant.aa_macro';
9 | match = '[a-zA-Z0-9]';
10 | },
11 | );
12 | },
13 | { name = 'meta.preprocessor.body.aa_macro';
14 | begin = '\<[a-zA-z]';
15 | end = '\>';
16 | },
17 | { name = 'meta.preprocessor.body.aa_macro';
18 | begin = '\[a-zA-z]';
19 | end = '\>';
20 | },
21 | { name = 'constant.character.escape.body.aa_macro';
22 | begin = '\{';
23 | end = '[\s|\}]';
24 | patterns = (
25 | { name = 'string.keyword.aa_macro';
26 | match = '[a-zA-Z0-9]';
27 | },
28 | );
29 | },
30 | { name = 'keyword.bodyc.aa_macro';
31 | match = '\]';
32 | },
33 | { name = 'constant.character.escape.bodyc.aa_macro';
34 | match = '\}';
35 | },
36 | );
37 | }
--------------------------------------------------------------------------------
/todo.md:
--------------------------------------------------------------------------------
1 | # [aa_macro.py](aa_macro.py)
2 |
3 | ## To Do for [aa_macro.py](aa_macro.py):
4 |
5 | * [load varName fileName] -- these have to obey the object forbid flag
6 | * [gload varName fileName]
7 | * convert intValue to "One Hundred Forty Three" etc. This seems non-trivial. :)
8 |
9 | ## To-do for Markdown-to-macro\(\) Filter
10 |
11 | Under development. Aiming primarily at github extensions and standard markdown
12 |
13 | ## To Do for Github's extensions:
14 |
15 | Generally complete to description at (Github's Cheatsheet)[https://enterprise.github.com/downloads/en/markdown-cheatsheet.pdf]
16 |
17 | ## To Do for standard markdown processing
18 |
19 | * hrules: `--- - - - *** * * * ___ _ _ _`
20 | * `"` should be untouched! don't entity-up amps in entities, but otherwise, do
21 | * <> only converted if not as a tag or thrown out in link-link syntax
22 | * `*` or `_` surround by spaces are literal
23 | * On header lines, all closing # must be stripped
24 | * Blockquotes can be nested (ugh)
25 | * \`\`-defined code spans
26 | * Literal backticks are allowed in \`\`-defined code spans
27 | * angle-links:
28 | * `` -- `URL` ... also works for email addresses
29 | * email entity encoding to fool some spambots
30 | * reference-style links:
31 | * `[text][id]` or `[text] [id]` <<< that's how you USE em
32 | * `[id][]` or implicit notation uses id for text
33 | * `[id]: URL` "optional title" <<< that's how you DEFINE them
34 | * link may be surrounded by optional `<>`
35 | * optional indent may be up to three spaces
36 | * single quotes, double quotes, or parens for title
37 | * these occur on single lines, or, title can be on next line
38 |
39 | * reference-style images:
40 | * `![alt/title text][id]` <<< USE
41 | * `[id]: URL`
42 |
43 | * lists can use \* OR \+ OR \-
44 | * markdown uses 1\. NOT 1\)
45 | * lists are valid with up to three spaces of indent
46 | * code blocks supported within list items
47 | * (done by indenting 8sp or 2t)
48 |
49 | * blockquotes supported inside list items
50 | * (done by indenting after list item 4sp or 1t)
51 |
52 | * paragraphs supported within list items
53 | * (done by separating list items with a blank line,
54 | * then indenting four space to start new paras)
55 |
56 | ## Github markdown processing
57 |
58 | ### Done:
59 |
60 | * code
61 | * fenced code blocks
62 | * four-leading-space code lines
63 | * tables
64 |
65 | ### To do:
66 |
67 | * task lists
68 |
69 | ### Punting unless use *on* Gitub seems possible:
70 |
71 | * username mentions \(Only useful as stands on Github\)
72 | * issue references \(Only useful on stands Github\)
73 |
74 | #### Alternate Filter for Github?
75 |
76 | Be nice if, when this is all said and done, I could have macro\(\) accepted
77 | as one of Github's supported filters. Somehow I doubt it, as they really
78 | lock down their HTML, but you never know.
79 |
--------------------------------------------------------------------------------
/unisample.txt:
--------------------------------------------------------------------------------
1 | [b bold]
2 | 🌮💩🍕🍝🍷🐱⚓🔗✅✔️☑️💃⚠️😊
3 | 🍆🥜
4 | [i italics]
5 |
--------------------------------------------------------------------------------
/unknown.syntax:
--------------------------------------------------------------------------------
1 | context default green blue
2 |
3 | define kcolor white
4 | define bcolor white
5 | define barcolor white
6 | define commacolor white
7 | define htmlcolor white
8 |
9 | define squigglycolor brightcyan
10 | define stylecolor red
11 |
12 | define bracecolor brightmagenta
13 | define builtincolor yellow
14 |
15 | keyword , commacolor
16 | keyword | barcolor
17 | keyword [b] yellow red
18 | keyword whole co builtincolor
19 | keyword whole sp builtincolor
20 | keyword whole lb builtincolor
21 | keyword whole rb builtincolor
22 | keyword whole ls builtincolor
23 | keyword whole rs builtincolor
24 | keyword whole nl builtincolor
25 | keyword whole lf builtincolor
26 | keyword parm\s10 yellow red
27 | keyword parm\s11 yellow red
28 | keyword parm\s12 yellow red
29 | keyword parm\s13 yellow red
30 | keyword parm\s14 yellow red
31 | keyword parm\s15 yellow red
32 | keyword parm\s0 yellow red
33 | keyword parm\s1 yellow red
34 | keyword parm\s2 yellow red
35 | keyword parm\s3 yellow red
36 | keyword parm\s4 yellow red
37 | keyword parm\s5 yellow red
38 | keyword parm\s6 yellow red
39 | keyword parm\s7 yellow red
40 | keyword parm\s8 yellow red
41 | keyword parm\s9 yellow red
42 | keyword >= green
43 | keyword <= green
44 | keyword [ bracecolor
45 | keyword ] bracecolor
46 | keyword { squigglycolor
47 | keyword } squigglycolor
48 |
49 | context < > htmlcolor
50 | keyword { squigglycolor
51 | keyword } squigglycolor
52 | keyword [ bracecolor
53 | keyword ] bracecolor
54 |
55 | context exclusive { \s stylecolor
56 | keyword { squigglycolor
57 | keyword } squigglycolor
58 | keyword [ bracecolor
59 | keyword ] bracecolor
60 | keyword parm\s10 yellow red
61 | keyword parm\s11 yellow red
62 | keyword parm\s12 yellow red
63 | keyword parm\s13 yellow red
64 | keyword parm\s14 yellow red
65 | keyword parm\s15 yellow red
66 | keyword parm\s0 yellow red
67 | keyword parm\s1 yellow red
68 | keyword parm\s2 yellow red
69 | keyword parm\s3 yellow red
70 | keyword parm\s4 yellow red
71 | keyword parm\s5 yellow red
72 | keyword parm\s6 yellow red
73 | keyword parm\s7 yellow red
74 | keyword parm\s8 yellow red
75 | keyword parm\s9 yellow red
76 | keyword >= green
77 | keyword <= green
78 |
79 | context exclusive [ \s builtincolor
80 | keyword { squigglycolor
81 | keyword } squigglycolor
82 | keyword [ bracecolor
83 | keyword ] bracecolor
84 | keyword parm\s10 yellow red
85 | keyword parm\s11 yellow red
86 | keyword parm\s12 yellow red
87 | keyword parm\s13 yellow red
88 | keyword parm\s14 yellow red
89 | keyword parm\s15 yellow red
90 | keyword parm\s0 yellow red
91 | keyword parm\s1 yellow red
92 | keyword parm\s2 yellow red
93 | keyword parm\s3 yellow red
94 | keyword parm\s4 yellow red
95 | keyword parm\s5 yellow red
96 | keyword parm\s6 yellow red
97 | keyword parm\s7 yellow red
98 | keyword parm\s8 yellow red
99 | keyword parm\s9 yellow red
100 | keyword >= green
101 | keyword <= green
102 |
103 | context exclusive { } green
104 | keyword [ bracecolor
105 | keyword ] bracecolor
106 | keyword { squigglycolor
107 | keyword } squigglycolor
108 | keyword parm\s10 yellow red
109 | keyword parm\s11 yellow red
110 | keyword parm\s12 yellow red
111 | keyword parm\s13 yellow red
112 | keyword parm\s14 yellow red
113 | keyword parm\s15 yellow red
114 | keyword parm\s0 yellow red
115 | keyword parm\s1 yellow red
116 | keyword parm\s2 yellow red
117 | keyword parm\s3 yellow red
118 | keyword parm\s4 yellow red
119 | keyword parm\s5 yellow red
120 | keyword parm\s6 yellow red
121 | keyword parm\s7 yellow red
122 | keyword parm\s8 yellow red
123 | keyword parm\s9 yellow red
124 | keyword >= green
125 | keyword <= green
126 |
--------------------------------------------------------------------------------
/users-guide.md:
--------------------------------------------------------------------------------
1 | # aa\_macro User's Guide
2 |
3 | Because...
4 |
5 | * [GitHub's pretty-printing support for new languages is non-existent](https://github.com/github/linguist/blob/master/CONTRIBUTING.md)
6 | * Because [markdown](https://daringfireball.net/projects/markdown/syntax) is underpowered
7 | * [dogfooding](https://en.wikipedia.org/wiki/Eating_your_own_dog_food)
8 |
9 | I've prepared the `aa_macro` manual using, what else, `aa_macro`,
10 | operating as a component of my [documentation system.](https://github.com/fyngyrz/wtfm)
11 |
12 | [Here it is.](http://ourtimelines.com/aamacrodoc/tocpage.html)
13 |
14 |
--------------------------------------------------------------------------------