├── 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 | ![macro\(\)](tease.png) 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 | ![Textmate Syntax](textmate-syntax.png) 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 | ![Leo](leo.png) 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 ![My Image](http://fyngyrz.com/images/beachflag.png) 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 = '\'; 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 | --------------------------------------------------------------------------------