Implement a facility to make wmlindent ignore designated stretches of lines.

Allow generation of XHTML docs from macro comments indented in the new format.
This commit is contained in:
Eric S. Raymond 2007-06-29 11:50:33 +00:00
parent 5f58e50664
commit 9433ae3fee
3 changed files with 212 additions and 196 deletions

View file

@ -49,79 +49,78 @@
#### END OF TABLE OF CONTENTS ####
#define QUANTITY ATTRIBUTE ON_EASY ON_NORMAL ON_HARD
# Macro to define a 'quantity' differently based on difficulty levels.
# Macro to define a 'quantity' differently based on difficulty levels.
#ifdef EASY
{ATTRIBUTE}={ON_EASY}
{ATTRIBUTE}={ON_EASY}
#endif
#ifdef NORMAL
{ATTRIBUTE}={ON_NORMAL}
{ATTRIBUTE}={ON_NORMAL}
#endif
#ifdef HARD
{ATTRIBUTE}={ON_HARD}
{ATTRIBUTE}={ON_HARD}
#endif
#enddef
#define TURNS ON_EASY ON_NORMAL ON_HARD
# Macro to define number of turns for different difficulty levels.
{QUANTITY turns {ON_EASY} {ON_NORMAL} {ON_HARD}}
# Macro to define number of turns for different difficulty levels.
{QUANTITY turns {ON_EASY} {ON_NORMAL} {ON_HARD}}
#enddef
#define GOLD ON_EASY ON_NORMAL ON_HARD
# Macro which will let you say {GOLD x y z} to set
# starting gold depending on easy/medium/hard - x/y/z
{QUANTITY gold {ON_EASY} {ON_NORMAL} {ON_HARD}}
# Macro which will let you say {GOLD x y z} to set
# starting gold depending on easy/medium/hard - x/y/z
{QUANTITY gold {ON_EASY} {ON_NORMAL} {ON_HARD}}
#enddef
#define INCOME ON_EASY ON_NORMAL ON_HARD
# Macro which will let you say {GOLD x y z} to set
# per-turn income depending on easy/medium/hard - x/y/z
{QUANTITY income {ON_EASY} {ON_NORMAL} {ON_HARD}}
# Macro which will let you say {GOLD x y z} to set
# per-turn income depending on easy/medium/hard - x/y/z
{QUANTITY income {ON_EASY} {ON_NORMAL} {ON_HARD}}
#enddef
#define ATTACK_DEPTH ON_EASY ON_NORMAL ON_HARD
# Macro to define AI attack depth for different difficulty levels
# (set it to 1-6)
{QUANTITY attack_depth {ON_EASY} {ON_NORMAL} {ON_HARD}}
# Macro to define AI attack depth for different difficulty levels
# (set it to 1-6)
{QUANTITY attack_depth {ON_EASY} {ON_NORMAL} {ON_HARD}}
#enddef
#define NO_SCOUTS
# Macro to make an AI team not recruit scouts.
villages_per_scout=0
# Macro to make an AI team not recruit scouts.
villages_per_scout=0
#enddef
#define RANDOM RANGE
# Macro to quickly pick a random value (in the $random variable, to avoid
# cluttering up savegames with such temporary variables).
[set_variable]
name=random
random={RANGE}
[/set_variable]
# Macro to quickly pick a random value (in the $random variable, to avoid
# cluttering up savegames with such temporary variables).
[set_variable]
name=random
random={RANGE}
[/set_variable]
#enddef
#define VARIABLE VAR VALUE
# Macro to initialize a variable. Strictly a syntatic shortcut.
[set_variable]
name={VAR}
value={VALUE}
[/set_variable]
# Macro to initialize a variable. Strictly a syntatic shortcut.
[set_variable]
name={VAR}
value={VALUE}
[/set_variable]
#enddef
#define VARIABLE_OP VAR OP ARG
# Macro to do mathematical operations on variables.
[set_variable]
name={VAR}
{OP}={ARG}
[/set_variable]
# Macro to do mathematical operations on variables.
[set_variable]
name={VAR}
{OP}={ARG}
[/set_variable]
#enddef
#define CLEAR_VARIABLE VAR
# Macro to clear a variable previously set.
[clear_variable]
name={VAR}
[/clear_variable]
# Macro to clear a variable previously set.
[clear_variable]
name={VAR}
[/clear_variable]
#enddef
# wmlindent: start ignoring
#define FOREACH ARRAY VAR
# Macro to begin a WML clause that iterates over an array.
{VARIABLE {VAR} 0}
@ -143,22 +142,23 @@ name={VAR}
[/while]
{CLEAR_VARIABLE {VAR}}
#enddef
# wmlindent: stop ignoring
#define DEBUG_MSG MSG
# Emit a debug message. Meant to be overridden with no-op definition
# of the same name for proction use.
[message]
speaker=narrator
message={MSG}
[/message]
# Emit a debug message. Meant to be overridden with no-op definition
# of the same name for proction use.
[message]
speaker=narrator
message={MSG}
[/message]
#enddef
#define MODIFY_UNIT FILTER VAR VALUE
# Alters a unit variable (such as unit.x, unit.type,
# unit.side), handling all the storing and unstoring.
#
# Example that flips all spearmen to side 2:
#! {MODIFY_UNIT type=Spearman side 2}
# Alters a unit variable (such as unit.x, unit.type,
# unit.side), handling all the storing and unstoring.
#
# Example that flips all spearmen to side 2:
#! {MODIFY_UNIT type=Spearman side 2}
[store_unit]
[filter]
{FILTER}
@ -169,26 +169,26 @@ message={MSG}
[/store_unit]
{FOREACH MODIFY_UNIT_store MODIFY_UNIT_i}
[set_variable]
name=MODIFY_UNIT_store[$MODIFY_UNIT_i].{VAR}
value={VALUE}
[/set_variable]
[set_variable]
name=MODIFY_UNIT_store[$MODIFY_UNIT_i].{VAR}
value={VALUE}
[/set_variable]
[unstore_unit]
variable=MODIFY_UNIT_store[$MODIFY_UNIT_i]
find_vacant=no
[/unstore_unit]
[unstore_unit]
variable=MODIFY_UNIT_store[$MODIFY_UNIT_i]
find_vacant=no
[/unstore_unit]
{NEXT MODIFY_UNIT_i}
{CLEAR_VARIABLE MODIFY_UNIT_store}
#enddef
#define STORE_UNIT_VAR FILTER VAR TO_VAR
# Stores an attribute of a unit to the given variable.
#
# Example where this is used to flip all orcs to whatever side James is on:
#! {STORE_UNIT_VAR description=James side side_of_James}
#! {MODIFY_UNIT race=orc side $side_of_James}
# Stores an attribute of a unit to the given variable.
#
# Example where this is used to flip all orcs to whatever side James is on:
#! {STORE_UNIT_VAR description=James side side_of_James}
#! {MODIFY_UNIT race=orc side $side_of_James}
[store_unit]
[filter]
{FILTER}
@ -204,21 +204,21 @@ message={MSG}
#enddef
#define IF_TERRAIN X Y TYPES CONTENTS
# This is a way to check whether or not the terrain in the given coordinates
# is of the given type or types. Might be useful, since filtering by terrain
# isn't possible directly.
#
# You can use it, for example, like this:
#! [event]
#! name=moveto
#! first_time_only=no
#!
#! {IF_TERRAIN $x1 $y1 gfm (
#! [then]
#! {DEBUG_MSG "Stepped on grassland, forest or mountains!"}
#! [/then]
#! )}
#! [/event]
# This is a way to check whether or not the terrain in the given coordinates
# is of the given type or types. Might be useful, since filtering by terrain
# isn't possible directly.
#
# You can use it, for example, like this:
#! [event]
#! name=moveto
#! first_time_only=no
#!
#! {IF_TERRAIN $x1 $y1 gfm (
#! [then]
#! {DEBUG_MSG "Stepped on grassland, forest or mountains!"}
#! [/then]
#! )}
#! [/event]
[store_locations]
x={X}
y={Y}
@ -239,39 +239,39 @@ message={MSG}
#enddef
#define CREATE_UNIT SIDE TYPE X Y UNIT_ID OTHER
# Creates a unit of TYPE belonging to SIDE at X,Y. UNIT_ID can be used
# when filtering on it. For example, let's create a wose for player 1
# at 4,7
#
#! {CREATE_UNIT 1 "Wose" 4 7 () ()}
#
# As a second example, let's make it a female wose which can recruit and
# is name "Woselina":
#
#! {CREATE_UNIT 1 "Wose" 4 7 "Woselina" (
# canrecruit=1
# )}
[unit]
side={SIDE}
type={TYPE}
x={X}
y={Y}
description={UNIT_ID}
user_description=" "
# Creates a unit of TYPE belonging to SIDE at X,Y. UNIT_ID can be used
# when filtering on it. For example, let's create a wose for player 1
# at 4,7
#
#! {CREATE_UNIT 1 "Wose" 4 7 () ()}
#
# As a second example, let's make it a female wose which can recruit and
# is name "Woselina":
#
#! {CREATE_UNIT 1 "Wose" 4 7 "Woselina" (
# canrecruit=1
# )}
[unit]
side={SIDE}
type={TYPE}
x={X}
y={Y}
description={UNIT_ID}
user_description=" "
upkeep=full
animate=yes
{OTHER}
[/unit]
upkeep=full
animate=yes
{OTHER}
[/unit]
#enddef
#define MOVE_UNIT FILTER TO_X TO_Y
# Moves a unit from its current location to the given location along a
# relatively straight line displaying the movement just like [move_unit_fake]
# does.
#
# Note that setting the destination on an existing unit does not kill either
# one, but causes the unit to move to the nearest vacant hex instead.
# Moves a unit from its current location to the given location along a
# relatively straight line displaying the movement just like [move_unit_fake]
# does.
#
# Note that setting the destination on an existing unit does not kill either
# one, but causes the unit to move to the nearest vacant hex instead.
[store_unit]
[filter]
{FILTER}
@ -293,10 +293,10 @@ message={MSG}
{VARIABLE MOVE_UNIT_temp.y {TO_Y}}
[kill]
{FILTER}
{FILTER}
animate=no
fire_event=no
animate=no
fire_event=no
[/kill]
[move_unit_fake]
@ -307,35 +307,34 @@ message={MSG}
[/move_unit_fake]
[unstore_unit]
variable=MOVE_UNIT_temp
find_vacant=yes
variable=MOVE_UNIT_temp
find_vacant=yes
[/unstore_unit]
[redraw][/redraw]
{CLEAR_VARIABLE MOVE_UNIT_temp}
{CLEAR_VARIABLE MOVE_UNIT_path_coords_x}
{CLEAR_VARIABLE MOVE_UNIT_path_coords_y}
{CLEAR_VARIABLE MOVE_UNIT_temp}
{CLEAR_VARIABLE MOVE_UNIT_path_coords_x}
{CLEAR_VARIABLE MOVE_UNIT_path_coords_y}
#enddef
#define PUT_TO_RECALL_LIST FILTER
# This places a given unit back to the recall list of the side it is on.
# Note however, that the unit is not healed to full health, so when
# recalled (even if not until the next scenario) the unit may have less
# than his maximum hp left.
#
# An example that returns all units stepping on (20,38) back to the recall
# list:
#
#! [event]
#! name=moveto
#!
#! [filter]
#! x,y=20,38
#! [/filter]
#!
#! {PUT_TO_RECALL_LIST x,y=20,38}
#! [/event]
# This places a given unit back to the recall list of the side it is on.
# Note however, that the unit is not healed to full health, so when
# recalled (even if not until the next scenario) the unit may have less
# than his maximum hp left.
#
# An example that returns all units stepping on (20,38) back to the recall
# list:
#
#! [event]
#! name=moveto
#!
#! [filter]
#! x,y=20,38
#! [/filter]
#!
#! {PUT_TO_RECALL_LIST x,y=20,38}
#! [/event]
[store_unit]
[filter]
{FILTER}
@ -346,57 +345,57 @@ message={MSG}
[/store_unit]
{FOREACH PUT_TO_RECALL_LIST_temp i}
{VARIABLE PUT_TO_RECALL_LIST_temp[$i].x "recall"}
{VARIABLE PUT_TO_RECALL_LIST_temp[$i].y "recall"}
{VARIABLE PUT_TO_RECALL_LIST_temp[$i].x "recall"}
{VARIABLE PUT_TO_RECALL_LIST_temp[$i].y "recall"}
[unstore_unit]
variable=PUT_TO_RECALL_LIST_temp[$i]
find_vacant=no
[/unstore_unit]
[unstore_unit]
variable=PUT_TO_RECALL_LIST_temp[$i]
find_vacant=no
[/unstore_unit]
{NEXT i}
#enddef
#define STARTING_VILLAGES SIDE RADIUS
# Macro to make a side start a scenario with villages
[event]
name=prestart
[store_starting_location]
side={SIDE}
variable=temp_starting_location
[/store_starting_location]
[store_locations]
x,y=$temp_starting_location.x,$temp_starting_location.y
radius={RADIUS}
#all the types of villages
[and]
terrain=Ha^Vhha, Hh^Vhh, Dd^Vda, Mm^Vhh, Uu^Vu, Aa^Vea, Gs^Vht, Uu^Vud, Gg^Ve, Dd^Vdt, Gg^Vh, Aa^Vha, Ww^Vm, Ss^Vhs, Ss^Vm
[/and]
variable=temp_starting_locs
[/store_locations]
# Macro to make a side start a scenario with villages
[event]
name=prestart
[store_starting_location]
side={SIDE}
variable=temp_starting_location
[/store_starting_location]
[store_locations]
x,y=$temp_starting_location.x,$temp_starting_location.y
radius={RADIUS}
#all the types of villages
[and]
terrain=Ha^Vhha, Hh^Vhh, Dd^Vda, Mm^Vhh, Uu^Vu, Aa^Vea, Gs^Vht, Uu^Vud, Gg^Ve, Dd^Vdt, Gg^Vh, Aa^Vha, Ww^Vm, Ss^Vhs, Ss^Vm
[/and]
variable=temp_starting_locs
[/store_locations]
{FOREACH temp_starting_locs i}
{FOREACH temp_starting_locs i}
{VARIABLE_OP temp_x_var to_variable temp_starting_locs[$i].x}
{VARIABLE_OP temp_y_var to_variable temp_starting_locs[$i].y}
[capture_village]
side={SIDE}
x,y=$temp_x_var,$temp_y_var
side={SIDE}
x,y=$temp_x_var,$temp_y_var
[/capture_village]
{NEXT i}
{NEXT i}
{CLEAR_VARIABLE temp_x_var}
{CLEAR_VARIABLE temp_y_var}
{CLEAR_VARIABLE temp_starting_location}
{CLEAR_VARIABLE temp_starting_locs}
{CLEAR_VARIABLE i}
[/event]
{CLEAR_VARIABLE temp_x_var}
{CLEAR_VARIABLE temp_y_var}
{CLEAR_VARIABLE temp_starting_location}
{CLEAR_VARIABLE temp_starting_locs}
{CLEAR_VARIABLE i}
[/event]
#enddef
#define UNIT TYPE DESCRIPTION UDESCRIPTION SIDE X Y
# Create a unit with the Loyal trait.
#
# Example:
#! {UNIT (Elvish Fighter) (Myname) ( _ "Myname") 1 1 1}
#
# Create a unit with the Loyal trait.
#
# Example:
#! {UNIT (Elvish Fighter) (Myname) ( _ "Myname") 1 1 1}
#
[unit]
type={TYPE}
description={DESCRIPTION}
@ -411,7 +410,7 @@ name=prestart
#enddef
#define UNDEAD_UNIT TYPE SIDE X Y
# Create a unit with the Undead and Loyal traits.
# Create a unit with the Undead and Loyal traits.
[unit]
type={TYPE}
side={SIDE}
@ -427,35 +426,35 @@ name=prestart
# FIXME: Documentation for these is needed.
#define MENU_IMG_TXT IMG TXT
"&"+{IMG}+"="+{TXT}#enddef
"&"+{IMG}+"="+{TXT}#enddef
#define MENU_IMG_TXT2 IMG TXT1 TXT2
"&"+{IMG}+"="+{TXT1}+"="+{TXT2}#enddef
"&"+{IMG}+"="+{TXT1}+"="+{TXT2}#enddef
#define TIME_ACTIONS CONTENTS
# Measure (in milliseconds) the time arbitrary event WML takes to execute.
# Afterwards, the time the enclosed WML took to execute is found in the variable
# $timed_actions_ms.
#
# Example:
#! [event]
#! name=start
#!
#! {TIME_ACTIONS (
#! {MODIFY_UNIT race=orc user_description ( _ "Azir")}
#! )}
#!
#! {DEBUG_MSG "Renaming all orcs to Azir took $timed_actions_ms|ms."}
#! [/event]
{VARIABLE_OP TIME_ACTIONS_time_begin time stamp}
# Measure (in milliseconds) the time arbitrary event WML takes to execute.
# Afterwards, the time the enclosed WML took to execute is found in the variable
# $timed_actions_ms.
#
# Example:
#! [event]
#! name=start
#!
#! {TIME_ACTIONS (
#! {MODIFY_UNIT race=orc user_description ( _ "Azir")}
#! )}
#!
#! {DEBUG_MSG "Renaming all orcs to Azir took $timed_actions_ms|ms."}
#! [/event]
{VARIABLE_OP TIME_ACTIONS_time_begin time stamp}
{CONTENTS}
{CONTENTS}
{VARIABLE_OP TIME_ACTIONS_time_end time stamp}
{VARIABLE_OP TIME_ACTIONS_time_end time stamp}
{VARIABLE timed_actions_ms $TIME_ACTIONS_time_end}
{VARIABLE_OP timed_actions_ms add "-$TIME_ACTIONS_time_begin"}
{VARIABLE timed_actions_ms $TIME_ACTIONS_time_end}
{VARIABLE_OP timed_actions_ms add "-$TIME_ACTIONS_time_begin"}
{CLEAR_VARIABLE TIME_ACTIONS_time_begin}
{CLEAR_VARIABLE TIME_ACTIONS_time_end}
#enddef
{CLEAR_VARIABLE TIME_ACTIONS_time_begin}
{CLEAR_VARIABLE TIME_ACTIONS_time_end}
#enddef

View file

@ -22,6 +22,11 @@ Runs of entirely blank lines will be reduced to one blank line, except
in two cases where they will be discarded: (a) before WML closing
tags, and (b) after WML opening tags.
It is possible to wrap a section of lines in special comments so that
wmlindent will ignore them. You may need to do this for unbalanced
macros (it'ds better, though, to get rid of those where possible.
Use 'wmlindent: {start,stop} ignoring' anywhere in a comment.
Interrupting will be safe, as each reindenting will be done to a copy
that is atomically renamed when it's done. If the output file is identical
to the input, the output file will simply be deleted, so the timestamp
@ -68,6 +73,7 @@ def reindent(name, infp, outfp):
dostrip = True
seen_wml = False
inmacro = False
ignoring = False
indent = ""
lasttag = ""
countlines = 0
@ -75,6 +81,16 @@ def reindent(name, infp, outfp):
multitag = re.compile(r"\[a-z]].*\[[a-z]") # Avoid triggering on arrays
for line in infp:
countlines += 1
# Implement passthrough mode
if "wmlindent: start ignoring" in line:
ignoring = True
outfp.write(line)
continue
elif ignoring:
outfp.write(line)
if "wmlindent: stop ignoring" in line:
ignoring = False
continue
# Detect things we can't handle
if multitag.search(line):
raise bailout(name, countlines, "multiple tags on the line")

View file

@ -151,7 +151,8 @@ class CrossRefLister(CrossRef):
hdr = []
dfp = open(filename)
for line in dfp:
if line[0] == '#':
line = line.lstrip()
if line and line[0] == '#':
hdr.append(line[1:])
else:
break