c# pdf viewer open source : Move pdf pages online control software system azure windows asp.net console World%20of%20Warcraft%20Programming%20(2nd%20Edition)38-part1836

Chapter 17
Creating Slash Commands 339
This is necessary only if you are making a change to a slash command handler that
you have already defined. It is not necessary when you’re firstcreating your new
command.
The details of the cache are beyond the scope ofthis chapter, butthe general
technique is described in Appendix A. You can also see the command handling
code for yourself in FrameXML\ChatFrame.lua.
Tokenizing Strings
Tokenization is the process of dividing a string into smallerpieces called tokens
based on certain rules. One of the simplest ways to accomplish this is with
the WoW-specific function
string.split
(or
strsplit
). This function splits a
string at occurrences of given delimiters. For example:
string.split(“ “, “1 + 3 * 5“)
This splits the given string at every space (the delimiter), returning the
tokens
“1“
,
“+“
,
“3“
,
“*“
,and
“5“
.
As theexamplehints,youcan createa simplecalculator usingthistechnique.
Create a new addon with just a Lua file or open up WowLua. To keep
the calculator simple, it will recognize only four operators: addition (+),
subtraction (–), multiplication (*), and division (/).Furthermore, there will be
no order of precedence of operations. In other words, 1 + 3 * 5 = 20, not 16.
The operations themselves are contained in a table indexed by the operator.
Enter the following code into WowLua or the new addon you created:
local operators = {
[“+“] = function(a, b)
return a + b
end,
[“-“] = function(a, b)
return a - b
end,
[“*“] = function(a, b)
return a * b
end,
[“/“] = function(a, b)
return a / b
end
}
Each operator simply accepts two numbers and returns the result of the
operation.Because alltheoperations proceedinorderofoccurrence,yourmain
Move pdf pages online - re-order PDF pages in C#.net, ASP.NET, MVC, Ajax, WinForms, WPF
Support Customizing Page Order of PDF Document in C# Project
move pages within pdf; how to change page order in pdf document
Move pdf pages online - VB.NET PDF Page Move Library: re-order PDF pages in vb.net, ASP.NET, MVC, Ajax, WinForms, WPF
Sort PDF Document Pages Using VB.NET Demo Code
pdf page order reverse; reorder pages pdf
340
Part III
Advanced Addon Techniques
calculation function can simply iteratethrough the returns of
string.split
as
follows:
local function calculate(number1, ...)
for i = 1, select(“#“, ...), 2 do
local operator, number2 = select(i, ...)
number1 = operators[operator](number1, number2)
end
return number1
end
The first number is placed into the variable
number1
.The loop begins by
retrieving the first operator and the second number. Then it calls the appro-
priateoperatorfunction with thetwogivennumbersandassigns thenewvalue
to
number1
.Each time through the loop it picks a new operator and second
number, and performs the calculation. Once it passes the last parameter, the
function returns the final value of
number1
.
Now all that’s left is to create the slash command to split the message and
print the result of the calculation:
SLASH_SIMPLECALC1 = “/calculate“
SLASH_SIMPLECALC2 = “/calc“
SlashCmdList[“SIMPLECALC“] = function(message)
print(calculate(string.split(“ “, message)))
end
Run the script or load the addon and you should be able to use the slash
commands as expected. Here are some examples:
/calculate 1 + 3 * 5
20
/calc 3 * 2 + 4 / 5.5
1.8181818181818
/calc 4
4
Obviouslythis is functional,butit has a coupleof pitfalls. Because thestring
is split at every occurrence of the space character, it’s as if there is an empty
string between any two consecutive spaces. For example:
/calculate 3
+ 4
Error: attempt to call field '?' (a nil value)
With the extra space between the
3
and the
+
,the string is split into the
tokens
“3“
,
““
,
“+“
,
“4“
.This means the
calculate
function tries to use
““
C# PDF File & Page Process Library SDK for C#.net, ASP.NET, MVC
Sorting Pages. RasterEdge XDoc.PDF allows you to easily move PDF document pages position, including sorting pages and swapping two pages.
move pages in pdf; pdf reorder pages
C# Word - Sort Word Pages Order in C#.NET
page reorganizing library control, developers can swap or adjust the order of all or several Word document pages, or just C# DLLs: Move Word Page Position.
move pages in pdf reader; move pages in pdf online
Chapter 17
Creating Slash Commands 341
as an index to the
operators
table, which is obviously an error. A similar
problem occurs if you omit a space:
/calc 3+4 * 5
Error: attempt to perform arithmetic on local 'a' (a string value)
Herethestring istokenizedinto
“3+4“
,
“*“
,and
“5“
.The
calculate
function
tries to call the multiplication operatorwith
“3+4“
as one of the numbers, again
an obvious error.
Although these drawbacks affect the usability of this calculator addon,
splitting on spaces is still sufficient for many purposes. Later in this chapter
you’ll use this technique again but in a much more powerful way. For now,
let’s relax the syntax for the calculator addon.
Tokenizing with Patterns
Parsing strings is a topic that can fill a volumein its own right. Many different
techniques exist depending on the complexity of your rules. Entire computer
languages have been designed specifically to describe the syntax of other lan-
guages. Although a full treatment is obviously beyond the scope of this book,
we can at least show you some of the tricks Lua brings to the table.
Chapter 6 provided a glimpse of Lua patterns that enable you to look for
specific arrangements of characters within a string. Now you’ll use them to
identify individual components of the calculator commands.
Setting Up the Patterns
First you should put the syntax of the commands into more definite terms.
The format for these commands is as follows:
number [ operator number [ operator number [ ... ] ]
This gives you the overall structure you need to follow when parsing the
string. Later you design the parsing functions to follow this general pattern.
Next you need to break down the format of each component. Operators are
simply one of the four operator characters. Numbers are a bit more complex:
[sign][digits][decimal]digits
From here, you can easily construct the patterns for each component. To
keep the code flexible, you won’t use a specialized pattern for the operators.
C# PowerPoint - Sort PowerPoint Pages Order in C#.NET
library control, developers can swap or adjust the order of all or several PowerPoint document pages, or just change the C# DLLs: Move PowerPoint Page Position.
move pages in pdf document; how to move pages in a pdf file
C# TIFF: How to Reorder, Rearrange & Sort TIFF Pages Using C# Code
Using this C#.NET Tiff image management library, you can easily change and move the position of any two or more Tiff file pages or make a totally new order for
reorder pdf pages reader; change pdf page order
342
Part III
Advanced Addon Techniques
Instead you’ll simply match any single character and check whetherit’s in the
list of operators. This means the pattern is simply a single period (
.
).
Table 17-1 shows the subpatterns that are used to create the final pattern of
“[+-]?%d*%.?%d+“
(see Chapter 6 for details).
Table 17-1: Number Subpatterns
COMPONENT
PATTERN
sign (optional)
[+-]?
digits (optional)
%d*
decimal (optional)
%.?
digits (required)
%d+
Now add the following code above any of the existing functions:
local NUMBER_PATTERN = “ˆ%s*([+-]?%d*%.?%d+)“
local OPERATOR_PATTERN = “ˆ%s*(.)“
local END_PATTERN = “ˆ%s*$“
Because the calculator will allow any amount of whitespace between num-
bers and operators, you put the target pattern inside parentheses to make it a
capture and precede it with a check for the optional whitespace:
%s*
.Notice
thatyouspecifythe beginning ofthestringimmediatelybefore the whitespace
(
ˆ
). If this weren’t in there, the pattern might skip over invalid syntax until it
finds a piece of valid syntax. Considerthe following example:
/calculate 5 + should error here 5
10
After processing the plus sign, your code would try to match the number
pattern against the string
“ should error here 5“
.Withoutthestart-of-string
check, the pattern will find a match at the end of the string:
“ 5“
,completely
ignoring the extraneous words.
You’ll also notice that we’ve added a pattern called
END_PATTERN
to handle
any extra space at the end of the command.
Preparing for the Tokenization
One helpful side-effect of doing in-depth parsing is the ease with which
you can check for errors. In this calculator addon two possible errors exist:
missing/invalid number or unrecognized operator. Add the following error
strings after the patterns you just created:
local NUMBER_ERROR = “No valid number at position %d“
local OPERATOR_ERROR = “Unrecognized operator at position %d: '%s'“
VB.NET PDF File & Page Process Library SDK for vb.net, ASP.NET
Certainly, random pages can be deleted from PDF file as well. PDF Page sorting. RasterEdge XDoc.PDF allows you to easily move PDF document pages position
rearrange pdf pages in preview; how to reorder pdf pages
C# PDF insert text Library: insert text into PDF content in C#.net
string to PDF files using online source codes int pageIndex = 0; // Move cursor to (400F, 100F outputFilePath = Program.RootPath + "\\" output.pdf"; doc.Save
how to move pdf pages around; move pages in pdf file
Chapter 17
Creating Slash Commands 343
Errors are indicated by a flag called
errorState
,which is set by a custom
error
function. Add the following code immediately before the
calculate
function:
local errorState = false
local function reportError(message)
print(message)
errorState = true
end
Now edit the
calculate
function to look like the following:
local function calculate(number1, ...)
if errorState then
return
end
for i = 1, select(“#“, ...), 2 do
local operatorFunction, number2 = select(i, ...)
number1 = operatorFunction(number1, number2)
end
return number1
end
If you’re already in an error state, then you just return and do nothing. The
last change you needtomakebeforediving intothe heart of the string parsing
is to clear the error state before calling the calculate function, and replace the
string.split
call with the new tokenize function you’ll be creating:
SlashCmdList[“SIMPLECALC“] = function(message)
errorState = false
print(calculate(tokenize(message)))
end
Parsing the Formula
The calculator formulas start off with a number and then are an optional
repetition of operator/number pairs. Your main
tokenize
function will pick
upthe first number and then call a second recursive function,
getpairs
,to ...
well .. . get the subsequent pairs.
Addthe
tokenize
functionbeforethe
SlashCmdList
entrywiththefollowing
code:
local function tokenize(message)
local _, finish, number = message:find(NUMBER_PATTERN)
if not number then
reportError(NUMBER_ERROR:format(1))
return
end
C# PDF Image Extract Library: Select, copy, paste PDF images in C#
edit, add, delete, move, and output PDF document image. Extract image from PDF free in .NET framework application with trial SDK components and online C# class
pdf reorder pages; rearrange pdf pages
VB.NET PDF Page Delete Library: remove PDF pages in vb.net, ASP.
Enable specified pages deleting from PDF in Visual Basic .NET class. Free trial SDK library download for Visual Studio .NET program. Online source codes for
reorder pages in pdf document; change page order in pdf file
344
Part III
Advanced Addon Techniques
The first line runs
string.find
to look for the first number in the formula
(remember every string has the
string
table as its metatable). If it doesn’t
find a number, it prints the error and returns. Finish the function with the
following code:
finish = finish + 1
if message:match(END_PATTERN, finish) == ““ then
return number
else
return number, getpairs(message, finish)
end
end
The
finish
variable contains the position of the last character in the found
number. In other words, if the formula is ‘‘
102 + 5
’’,
finish
would be 3,
corresponding to the 2 in 102. The first line of this code increments
finish
by
one to indicate the start of the rest of the message.
Next it looks for
END_PATTERN
in the message, starting at the new location.
If it matches,
tokenize
returns the number it found. Otherwise it returns the
number andcalls
getpairs
toparse the restofthe message.Begin thisfunction
just above
tokenize
:
local function getpairs(message, start)
local _, operatorFinish, operator = message:find(OPERATOR_PATTERN, i
start)
local operatorFunction = operators[operator]
if not operatorFunction then
reportError(OPERATOR_ERROR:format(start, operator))
return
end
As you can see, this checks for a valid operator and triggers an error if
it’s not recognized. Next, search for a number from the position just past the
operator:
operatorFinish = operatorFinish + 1
local _, numberFinish, number = message:find(NUMBER_PATTERN,
i
operatorFinish)
if not number then
reportError(NUMBER_ERROR:format(operatorFinish))
return
end
And finally, finish the function just like
tokenize
:
numberFinish = numberFinish + 1
if message:match(END_PATTERN, numberFinish) then
return operatorFunction, number
else
Chapter 17
Creating Slash Commands 345
return operatorFunction, number, getpairs(message, numberFinish)
end
end
After reloading, you can see the earlier errors are now fixed, and bona fide
errors have sane messages:
/calculate 3
+ 4
7
/calc 3+4 * 5
35
/calc 3+ 4 +
No valid number at position 7
/calc 3 + 4 & 9
Unrecognized operator at position 7: `&'
Using a Command Table
Some addons provide a single slash command with multiple, possibly nested
subcommands. For example, to show the GUI for Omen, you would use the
following command:
/omen gui show
You can easily create this kind of functionality with a relatively simple
parsing system that uses a table to represent the command hierarchy. The
parseryoudevelophere uses a tableindexedwith the name ofthe commands.
Each entry in the table is a string, a function, or a table. If the command is a
string value, it is printed as-is. If the command is a function, the parser calls
the function with the rest of the slash command’s message. If the command is
atable, the parser treats it as another command table and processes the rest
of the message against it. If the command isn’t found, the parser looks for an
entry called ‘‘help’’ and processes it as usual.
Goaheadand createa new addon with justa Luafileand enterthefollowing
example table:
local testCommandTable = {
[“gui“] = {
[“width“] = function(width)
print(“Setting width to“, width)
end,
[“height“] = function(height)
print(“Setting height to“, height)
end,
[“show“] = function()
print(“Showing“)
346
Part III
Advanced Addon Techniques
end,
[“hide“] = function()
print(“Hiding“)
end,
[“help“] = “GUI commands: width <width>, height <height>, show, i
hide“
},
[“data“] = {
[“load“] = function(profile)
print(“Loading profile:“, profile)
end,
[“save“] = function(profile)
print(“Saving profile: “, profile)
end,
[“reset“] = function()
print(“Resetting to default“)
end,
[“help“] = “Data commands: load <profile>, save <profile>, reset“
},
[“help“] = “CommandTable commands: gui, data“
}
As you can see, this is a very concise way of defining a wide range of
functionality. That is, once you get the engine out of the way. Begin the
command processing function with the following code:
local function DispatchCommand(message, commandTable)
local command, parameters = string.split(“ “, message, 2)
local entry = commandTable[command:lower()]
local which = type(entry)
The first line of the function splits the message at the first space. Notice the
extra argument of
2
,which tells
string.split
to return a maximum of two
strings, limiting the number of splits.
The next line retrieves the entry from the given command table, then the
function determines what type of entry it is. The rest of the function is
essentially a restatement in Lua of our earlier description:
if which == “function“ then
entry(parameters)
elseif which == “table“ then
DispatchCommand(parameters or ““, entry)
elseif which == “string“ then
print(entry)
elseif message ~= “help“ then
DispatchCommand(“help“, commandTable)
end
end
Chapter 17
Creating Slash Commands 347
Now all youneed to do is tie it together with a slash command:
SLASH_COMMANDTABLE1 = “/commandtable“
SLASH_COMMANDTABLE2 = “/cmdtbl“
SlashCmdList[“COMMANDTABLE“] = function(message)
DispatchCommand(message, testCommandTable)
end
And voila! Twenty-one lines of code later and you have a powerful slash
command handler that uses a simple table for configuration. Here is some
sample output:
/cmdtbl gui show
Showing
/commandtable data
Data commands: load <profile>, save <profile>, reset
/cmdtbl GUI Width 13
Setting width to 13
Summary
In this chapter you learned the basics of slash commands and how to get
a barebones command up and running. You also examined a set of tips
and tricks you can use to make your code more flexible and cleaner. Slash
commands aren’t flashy, and in some circles they get a bad rap, but they’re
powerful, flexible, and, if implemented correctly, elegant. One very powerful
aspect of slash commands versus graphical configuration interfaces is that
slash commands can be usedin macros, allowing userstochange theirsettings
on-the-fly using buttons on their action bars.
The Code
SlashCalc
local NUMBER_PATTERN = “
ˆ
%s*([+-]?%d*%.?%d+)“
local OPERATOR_PATTERN = “ˆ%s*(.)“
local END_PATTERN = “ˆ%s*$“
local NUMBER_ERROR = “No valid number at position %d“
local OPERATOR_ERROR = “Unrecognized operator at position %d: '%s'“
local errorState = false
348
Part III
Advanced Addon Techniques
local function reportError(message)
print(message)
errorState = true
end
local operators = {
[“+“] = function(a, b)
return a + b
end,
[“-“] = function(a, b)
return a - b
end,
[“*“] = function(a, b)
return a * b
end,
[“/“] = function(a, b)
return a / b
end
}
local function calculate(number1, ...)
if errorState then
return
end
for i = 1, select(“#“, ...), 2 do
local operatorFunc, number2 = select(i, ...)
number1 = operatorFunc(number1, number2)
end
return number1
end
local function getpairs(message, start)
local _, operatorFinish, operator = i
message:find(OPERATOR_PATTERN, start)
local operatorFunction = operators[operator]
if not operatorFunction then
reportError(OPERATOR_ERROR:format(start, operator))
return
end
operatorFinish = operatorFinish + 1
local _, numberFinish, number = message:find(NUMBER_PATTERN, i
operatorFinish)
if not number then
reportError(NUMBER_ERROR:format(operatorFinish))
return
end
Documents you may be interested
Documents you may be interested