/usr/share/pyshared/kiki.py is in kiki 0.5.6-8fakesync1.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 | """Kiki 0.5.6 - A Free Environment for Regular Expression Testing (ferret)
Copyright (C) 2003, 2004 Project 5
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
Contact info
web: http://come.to/project5
mail/msn: project5@wanadoo.nl
icq: 84243714
"""
import wxversion
wxversion.select('2.8')
import wx
import wx.html
__version__ = "0.5.6"
import re, os, os.path, cgi, sys
# string constants
WINDOWSIZE = "MainWindowSize"
WINDOWPOSITION = "MainWindowPosition"
SASHPOSITION = "SashPosition"
SEARCHTYPE = "SearchType"
MATCHINDEX = "MatchIndex"
MATCHTEMPLATE = "MatchTemplate"
FORMATTEDMATCH = "FormattedMatch"
STARTTEMPLATE = "StartTemplate"
ENDTEMPLATE = "EndTemplate"
GROUPCOLOR = "GroupColor"
GROUPNUMBER = "GroupNumber"
SAMPLETEXT = "SampleText"
REGEX = "Regex"
RESULTS_SHOWMATCHES = "ShowMatchesGroups"
RESULTS_SHOWNAMEDGROUPS = "ShowNamedGroups"
RESULTS_SHOWSAMPLE = "ShowSampleTextInResults"
# flags below are used in settings and in eval() function, so do NOT change!
FLAGIGNORE = "re.IGNORECASE"
FLAGMULTILINE = "re.MULTILINE"
FLAGLOCALE = "re.LOCALE"
FLAGDOTALL = "re.DOTALL"
FLAGUNICODE = "re.UNICODE"
FLAGVERBOSE = "re.VERBOSE"
# constants required by the GUI
ni = wx.NewId
ID_EVALUATE = ni()
ID_NOTEBOOK = ni()
ID_HELPCOMBOBOX = ni()
# global variable
settings = None
# templates
t_error = """<font color="maroon"><b>Error:</b></font><br /><ul>%s</ul>"""
t_nomatch = """<font color="teal"><b>No match found</b></font>"""
# colors used to highlight matches
colors = ["0000AA" , "00AA00" , "FFAA55" , "AA0000" , "00AAAA" , "AA00AA" , "AAAAAA" ,
"0000FF" , "00FF00" , "00FFFF" , "FF0000" , "DDDD00" , "FF00FF" ,
"AAAAFF" , "FF55AA" , "AAFF55" , "FFAAAA" , "55AAFF" , "FFAAFF" ,
"000077" , "007700" , "770000" , "007777" , "770077" , "777700" ]
class Settings(object):
"""Stores and retrieves settings to a file as Python data
structures which are eval()-ed. This is not by definition
safe, but since the user has access to source code anyway
and hence the ability to screw up anything, the danger
seems quite limited."""
def __init__(self, savedir=None, dirname="", filename="settings.py", debugfile=""):
"""Initializes the object
Arguments:
savedir -- directory where to store data
For more info, see the docs of Settings.setSaveDir()
dirname -- if savedir=None, dirname is used to determine which
subdirectory of $HOME data is stored it.
filename -- name of file containing stored data
debugfile -- used to allow the user to manually override the
default storage dir. Mor info in the docs of
Settings.setSaveDir()
"""
self.__setSaveDir(savedir, dirname, debugfile)
self.savefilename = filename
self.__load()
def shutdown(self):
"""Must be called before the program ends."""
self.save()
def __setSaveDir(self, savedir=None, dirname="", debugfile=""):
"""Sets self.savedir
Arguments:
savedir -- directory where to store data
if savedir==None, $HOME/dirname is used.
If necessary, the directory is created.
dirname -- if savedir==None, dirname determines which
subdirectory of the home dir data is stored
in
debugfile -- this file may be a filename which is imported
and may contain a variable called savedir
If the debugfile is specified, imported
successfully and savedir exists, it is used
to override any other parameters. This allows
users to override the directory, bypassing
the application which needs the settings.
In some Windows installations (seems to be mainly a Win2k
problem), $HOME points to the root directory. In this case,
this function will try to use $USERPROFILE/dirname instead.
Overriding this default behaviour is possible by supplying the
savedir variable in pearsdebug.py."""
if savedir==None:
try: # try to override using debugfile if present and contains savedir
debugmodule = __import__(debugfile, globals())
savedir = debugmodule.savedir
except: # if no override, then perform default actions
if savedir == None: # use $HOME/dirname
savedir = os.path.expanduser('~/'+dirname)
if len(savedir)<=len("c:\\/"+dirname): # sometimes $HOME points to root
# if this is the case, try using $USERPROFILE (see docstring)
temp = os.path.join(os.path.expandvars('$USERPROFILE'), dirname)
# if this is a different location, use it!
if temp > len("C:\\/"+dirname):
savedir = temp
# create dir if it doesn't exist
if not os.path.exists(savedir):
os.makedirs(savedir)
self.savedir = savedir
def __load(self):
"""Loads the settings from a file. These settings are saved
in Python code format which is eval()-ed, so it's not
trustworthy."""
try:
settingsfile = file(os.path.join(self.savedir, self.savefilename), "r")
self.settings = eval(settingsfile.read())
settingsfile.close()
except: # if file doesn't exist
self.settings= {}
def save(self):
"""Saves the settings to a file."""
settingsfile = file(os.path.join(self.savedir, self.savefilename), "w")
settingsfile.write(str(self.settings))
settingsfile.close()
def set(self, settingname, value):
"""Changes the value of a setting with settingname to value."""
self.settings[settingname] = value
def get(self, settingname, defaultval=None):
"""Returns the setting with settingname if present, otherwise
returns defaultval and saves settingname with defaultval."""
if self.settings.has_key(settingname):
return self.settings[settingname]
else:
self.set(settingname, defaultval)
return defaultval
class MyHtmlWindow(wx.html.HtmlWindow):
"""Adds OnLinkClicked"""
def __init__(self, parent, id):
wx.html.HtmlWindow.__init__(self, parent, id, style=wx.NO_FULL_REPAINT_ON_RESIZE)
def OnLinkClicked(self, linkinfo):
# there's a problem in KDE: the browser is not recognized properly
# circumvent this problem
import os
if os.environ.has_key("BROWSER") and \
os.environ["BROWSER"]=='kfmclient openProfile webbrowsing':
print "Invalid browser detected : %s\nResetting to konqueror." % os.environ["BROWSER"]
os.environ["BROWSER"] = 'konqueror' # set it to konqueror
import webbrowser # MUST be imported only AFTER os.environ has been modified
webbrowser.open(linkinfo.GetHref(), 1)
class MyFrame(wx.Frame):
def __init__(self, *args, **kwds):
# begin wxGlade: MyFrame.__init__
kwds["style"] = wx.DEFAULT_FRAME_STYLE
wx.Frame.__init__(self, *args, **kwds)
self.SplitterWindow = wx.SplitterWindow(self, -1, style=wx.SP_3D|wx.SP_LIVE_UPDATE)
self.BottomPane = wx.Panel(self.SplitterWindow, -1)
self.Notebook = wx.Notebook(self.BottomPane, ID_NOTEBOOK, style=0)
self.HelpPane = wx.Panel(self.Notebook, -1)
self.SampleTextPane = wx.Panel(self.Notebook, -1)
self.MatchesPane = wx.Panel(self.Notebook, -1, style=wx.SUNKEN_BORDER|wx.TAB_TRAVERSAL)
self.TopPane = wx.Panel(self.SplitterWindow, -1, style=wx.RAISED_BORDER|wx.TAB_TRAVERSAL)
self.RegexBox = wx.ComboBox(self.TopPane, -1, choices=["", "", "", "", "", "", ""], style=wx.CB_DROPDOWN)
self.EvaluateButton = wx.Button(self.TopPane, ID_EVALUATE, "Evaluate")
self.MethodBox = wx.RadioBox(self.TopPane, -1, "Methods", choices=["Find all", "Find first"], majorDimension=1, style=wx.RA_SPECIFY_COLS)
self.IgnoreCheckBox = wx.CheckBox(self.TopPane, -1, "IGNORECASE (I)")
self.LocaleCheckBox = wx.CheckBox(self.TopPane, -1, "LOCALE (L)")
self.MultilineCheckBox = wx.CheckBox(self.TopPane, -1, "MULTILINE (M)")
self.DotAllCheckBox = wx.CheckBox(self.TopPane, -1, "DOTALL (S)")
self.UnicodeCheckBox = wx.CheckBox(self.TopPane, -1, "UNICODE (U)")
self.VerboseCheckBox = wx.CheckBox(self.TopPane, -1, "VERBOSE (X)")
self.MatchesWindow = wx.html.HtmlWindow(self.MatchesPane, -1)
self.SampleText = wx.TextCtrl(self.SampleTextPane, -1, "", style=wx.TE_PROCESS_TAB|wx.TE_MULTILINE|wx.TE_RICH)
self.HelpSelection = wx.ComboBox(self.HelpPane, ID_HELPCOMBOBOX, choices=["Working with Kiki", "Re - syntax", "Re - special characters: |, (, +, etc.", "Re - extensions, groups and lookahead/lookbehind: (?...)", "Re - special sequences: \...", "Re - flags", "About Kiki"], style=wx.CB_DROPDOWN|wx.CB_READONLY)
self.HelpWindow = MyHtmlWindow(self.HelpPane, -1)
self.__set_properties()
self.__do_layout()
# end wxGlade
def __set_properties(self):
# begin wxGlade: MyFrame.__set_properties
self.SetTitle("Kiki")
self.SetSize((640, 480))
self.RegexBox.SetSelection(0)
self.EvaluateButton.SetDefault()
self.MethodBox.SetToolTipString("Find all returns all matches, find first only the first one")
self.MethodBox.SetSelection(0)
self.IgnoreCheckBox.SetToolTipString("Perform case-insensitive matching\nExpressions like [A-Z] will match lowercase letters too. This is not affected by the current locale.")
self.LocaleCheckBox.SetToolTipString("Make \w, \W, \\b, and \B dependent on the current locale.")
self.MultilineCheckBox.SetToolTipString("When specified, the pattern characters \"^\" and \"$\" match at the beginning respectively end of the string and at the beginning respectively end of each line (immediately following respectively preceding each newline).\nOtherwise \"^\" matches only at the beginning of the string, and \"$\" only at the end of the string and immediately before the newline (if any) at the end of the string.")
self.DotAllCheckBox.SetToolTipString("Make the \".\" special character match any character at all, including a newline. Without this flag, \".\" will match anything except a newline.")
self.UnicodeCheckBox.SetToolTipString("Make \w, \W, \\b, and \B dependent on the Unicode character properties database.")
self.VerboseCheckBox.SetToolTipString("This flag allows you to write regular expressions that look nicer.\nWhitespace within the pattern is ignored, except when in a character class or preceded by an unescaped backslash, and, when a line contains a \"#\" neither in a character class or preceded by an unescaped backslash, all characters from the leftmost such \"#\" through the end of the line are ignored. ")
self.HelpSelection.SetSelection(0)
self.BottomPane.SetSize((623, 324))
self.SplitterWindow.SplitHorizontally(self.TopPane, self.BottomPane, 120)
# end wxGlade
def __do_layout(self):
# begin wxGlade: MyFrame.__do_layout
MainSizer = wx.BoxSizer(wx.HORIZONTAL)
TopPaneSizer = wx.BoxSizer(wx.HORIZONTAL)
HelpPaneSizer = wx.FlexGridSizer(3, 1, 7, 7)
SampleTextSizer = wx.BoxSizer(wx.HORIZONTAL)
MatchesPaneSizer = wx.BoxSizer(wx.HORIZONTAL)
BottomPaneSizer = wx.FlexGridSizer(5, 3, 0, 0)
OptionsSizer = wx.FlexGridSizer(1, 2, 0, 7)
FlagsSizer = wx.StaticBoxSizer(wx.StaticBox(self.TopPane, -1, "Flags"), wx.HORIZONTAL)
FlagCheckSizer = wx.FlexGridSizer(4, 3, 7, 15)
RegexSizer = wx.FlexGridSizer(1, 2, 0, 7)
BottomPaneSizer.Add((7, 7), 0, wx.EXPAND, 0)
BottomPaneSizer.Add((7, 7), 0, wx.EXPAND, 0)
BottomPaneSizer.Add((7, 7), 0, wx.EXPAND, 0)
BottomPaneSizer.Add((7, 7), 0, wx.EXPAND, 0)
RegexSizer.Add(self.RegexBox, 0, wx.EXPAND, 0)
RegexSizer.Add(self.EvaluateButton, 0, 0, 0)
RegexSizer.AddGrowableCol(0)
BottomPaneSizer.Add(RegexSizer, 1, wx.EXPAND, 0)
BottomPaneSizer.Add((7, 7), 0, wx.EXPAND, 0)
BottomPaneSizer.Add((7, 7), 0, wx.EXPAND, 0)
BottomPaneSizer.Add((7, 7), 0, wx.EXPAND, 0)
BottomPaneSizer.Add((7, 7), 0, wx.EXPAND, 0)
BottomPaneSizer.Add((7, 7), 0, wx.EXPAND, 0)
OptionsSizer.Add(self.MethodBox, 0, wx.EXPAND, 0)
FlagCheckSizer.Add((7, 2), 0, wx.EXPAND, 0)
FlagCheckSizer.Add((7, 2), 0, wx.EXPAND, 0)
FlagCheckSizer.Add((7, 2), 0, wx.EXPAND, 0)
FlagCheckSizer.Add(self.IgnoreCheckBox, 0, 0, 0)
FlagCheckSizer.Add(self.LocaleCheckBox, 0, 0, 0)
FlagCheckSizer.Add(self.MultilineCheckBox, 0, 0, 0)
FlagCheckSizer.Add(self.DotAllCheckBox, 0, 0, 0)
FlagCheckSizer.Add(self.UnicodeCheckBox, 0, 0, 0)
FlagCheckSizer.Add(self.VerboseCheckBox, 0, 0, 0)
FlagCheckSizer.Add((7, 2), 0, wx.EXPAND, 0)
FlagCheckSizer.Add((7, 2), 0, wx.EXPAND, 0)
FlagCheckSizer.Add((7, 2), 0, wx.EXPAND, 0)
FlagsSizer.Add(FlagCheckSizer, 1, wx.EXPAND, 0)
OptionsSizer.Add(FlagsSizer, 1, 0, 0)
BottomPaneSizer.Add(OptionsSizer, 1, wx.EXPAND, 0)
BottomPaneSizer.Add((7, 7), 0, wx.EXPAND, 0)
BottomPaneSizer.Add((7, 7), 0, wx.EXPAND, 0)
BottomPaneSizer.Add((7, 7), 0, wx.EXPAND, 0)
BottomPaneSizer.Add((7, 7), 0, wx.EXPAND, 0)
self.TopPane.SetAutoLayout(1)
self.TopPane.SetSizer(BottomPaneSizer)
BottomPaneSizer.Fit(self.TopPane)
BottomPaneSizer.SetSizeHints(self.TopPane)
BottomPaneSizer.AddGrowableCol(1)
MatchesPaneSizer.Add(self.MatchesWindow, 1, wx.EXPAND, 0)
self.MatchesPane.SetAutoLayout(1)
self.MatchesPane.SetSizer(MatchesPaneSizer)
MatchesPaneSizer.Fit(self.MatchesPane)
MatchesPaneSizer.SetSizeHints(self.MatchesPane)
SampleTextSizer.Add(self.SampleText, 1, wx.EXPAND, 0)
self.SampleTextPane.SetAutoLayout(1)
self.SampleTextPane.SetSizer(SampleTextSizer)
SampleTextSizer.Fit(self.SampleTextPane)
SampleTextSizer.SetSizeHints(self.SampleTextPane)
HelpPaneSizer.Add((1, 1), 0, wx.EXPAND, 0)
HelpPaneSizer.Add(self.HelpSelection, 0, wx.EXPAND, 0)
HelpPaneSizer.Add(self.HelpWindow, 1, wx.EXPAND, 0)
self.HelpPane.SetAutoLayout(1)
self.HelpPane.SetSizer(HelpPaneSizer)
HelpPaneSizer.Fit(self.HelpPane)
HelpPaneSizer.SetSizeHints(self.HelpPane)
HelpPaneSizer.AddGrowableRow(2)
HelpPaneSizer.AddGrowableCol(0)
self.Notebook.AddPage(self.MatchesPane, "Matches")
self.Notebook.AddPage(self.SampleTextPane, "Sample text")
self.Notebook.AddPage(self.HelpPane, "Help")
TopPaneSizer.Add(self.Notebook, 1, wx.EXPAND, 0)
self.BottomPane.SetAutoLayout(1)
self.BottomPane.SetSizer(TopPaneSizer)
MainSizer.Add(self.SplitterWindow, 1, wx.EXPAND, 0)
self.SetAutoLayout(1)
self.SetSizer(MainSizer)
self.Layout()
self.Centre()
# end wxGlade
# end of class MyFrame
class MyFrameWithEvents(MyFrame):
"""Subclasses MyFrame - generated by wxGlade - and adds events."""
def __init__(self, *args, **kwargs):
MyFrame.__init__(self, *args, **kwargs)
# map option flags to checkboxes
self.flagmapper = {FLAGIGNORE: self.IgnoreCheckBox,
FLAGMULTILINE: self.MultilineCheckBox,
FLAGLOCALE: self.LocaleCheckBox,
FLAGDOTALL: self.DotAllCheckBox,
FLAGUNICODE: self.UnicodeCheckBox,
FLAGVERBOSE: self.VerboseCheckBox}
self.SetTitle(" " + self.GetTitle() + " " + __version__)
# set empty pages for HTML windows
self.MatchesWindow.SetPage("")
self.HelpWindow.SetPage("")
self.HelpWindow.SetWindowStyleFlag(wx.SUNKEN_BORDER)
self.Notebook.SetSelection(0)
self.RegexBox.Clear()
# bind events
wx.EVT_BUTTON(self, ID_EVALUATE, self.evaluate)
wx.EVT_CLOSE(self, self.close)
wx.EVT_NOTEBOOK_PAGE_CHANGED(self, ID_NOTEBOOK, self.changePage)
wx.EVT_COMBOBOX(self, ID_HELPCOMBOBOX, self.showhelp)
# apply settings
self.loadSettings()
# move focus to regex input field
self.RegexBox.SetFocus()
# initialize needed attribs
self.matches = [] # list of found matches
self.path = os.path.split(sys.argv[0])[0] or os.getcwd() # remembers where Kiki is located
self.doc_path = "/usr/share/doc/kiki"
def icon(self, path=None):
"""Load and assign the icon
Arguments:
path -- path where kiki.ico is located. If
path==None, the current directory is
used
"""
import sys
if path==None:
self.path = os.path.split(sys.argv[0])[0] or os.getcwd() # *MUST* be the directory where everything, including About data and the likes are located
else:
self.path = path
iconfile = "/usr/share/pixmaps/kiki.xpm"
theicon = wx.Icon(iconfile, wx.BITMAP_TYPE_XPM)
self.SetIcon(theicon)
def changePage(self, event):
"""Handles notebook page changes"""
if event.GetSelection()==2 and not self.HelpWindow.GetOpenedPageTitle().strip():
self.HelpWindow.SetPage(file(os.path.join(self.doc_path, "index.html"),"r").read())
def showhelp(self, event):
"""Handles help combo box events"""
sel = self.HelpSelection.GetStringSelection().lower() # must lower-case for comparisons
id = self.HelpSelection.GetSelection()
filename, anchor = "", ""
simpleload = True
if id==0: # show main help
filename = "index.html"
elif sel.find("syntax")>-1:
filename, anchor = "re.html", "syntax"
elif sel.find("special characters")>-1:
filename, anchor = "re.html", "specialcharacters"
elif sel.find("extensions")>-1:
filename, anchor = "re.html", "extensions"
elif sel.find("special sequences")>-1:
filename, anchor = "re.html", "specialsequences"
elif sel.find("flags")>-1:
filename, anchor = "re.html", "flags"
else:
simpleload = False
if simpleload:
filename = os.path.join(self.doc_path, filename)
if anchor.strip():
anchor = "#" + anchor
else:
anchor = ""
self.HelpWindow.LoadPage(filename+anchor)
else: # build about-screen
f = file(os.path.join(self.doc_path, "about.html"), "r")
about = f.read()
f.close()
# build the dictionary needed to format the string
if self.GetTitle().lower().find("spe")>-1:
spe = "active"
else: spe = "inactive (Kiki running standalone)"
d = {"version": __version__,
"kikidir": self.path,
"datadir": settings.savedir,
"pythonversion": sys.version.split()[0],
"wxpythonversion": wx.__version__,
"spe": spe,
"website": "http://come.to/project5",
"mail": "project5@wanadoo.nl",
"icq": "84243714" }
about = about % d
self.HelpWindow.SetPage(about)
def evaluate(self, event):
"""Actual functionality, triggered by Evaluate button press.
The regex is compiled if possible.
If compilation is successful, the regex is added to the
history and it's matched against the sample text.
If compilation is unsuccessful, the error message is
displayed.
"""
self.saveSettings()
self.Notebook.SetSelection(0) # display output pane
# STEP 1: try to compile the regex
# get flags to use in the compilation
flags = 0
for flag in self.flagmapper.keys():
if self.flagmapper[flag].IsChecked():
flags = flags|eval(flag)
# compile the regex and stop with error message if invalid
try:
self.MatchesWindow.SetPage("")
regex = re.compile(self.RegexBox.GetValue(), flags)
except re.error, e:
self.MatchesWindow.SetPage(t_error % e)
return False # stop execution if error
if self.RegexBox.GetValue().strip(): # append to history if non-empty
# get current history items
currentitems = [self.RegexBox.GetValue()]
for i in range(self.RegexBox.GetCount()):
t = self.RegexBox.GetString(0)
if not t in currentitems: # no duplicates
currentitems.append(t)
self.RegexBox.Delete(0)
for item in currentitems:
self.RegexBox.Append(item)
self.RegexBox.SetSelection(0) # set selection again
rawtext = self.SampleText.GetValue()
# insider joke for the Sluggy fans
if rawtext.strip()=="INSTANT FERRET-SHOCK!":
import random
shock = ["<b>"]
#blinkychars = """+*-/\:;][{}|tyqfghjkl?>ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890!@#$%"""
rc = random.choice
c = colors
sa = shock.append
t = """<font color="#%s">KIKI</font>"""
[ sa(t % (rc(c))) for i in xrange(10000) ]
shock.append("</b>")
self.MatchesWindow.SetPage("".join(shock))
return None
self.matches = [] # empty the list of match objects
output = []
while 1:
if len(self.matches)==0:
start = 0
else:
start = self.matches[-1].end()
if len(self.matches[-1].group(0))==0:
# in case of expressions which return empty matches
# Without this condition, an endless loop would occur.
start += 1
match = regex.search(rawtext, start)
if (not match) or \
(len(self.matches)>=1 and self.MethodBox.GetSelection()==1) or \
start>=len(rawtext): # this last condition is also to prevent an endless loop
break # stop execution
else:
self.matches.append(match)
if not self.matches: # if no matches found
output.append(t_nomatch)
else: # matches found
# show matches with parentheses
if settings.get(RESULTS_SHOWMATCHES, True):
output.append(self.showmatches())
output.append("""<br /><br />""")
# show tabular overview of named groups
if settings.get(RESULTS_SHOWNAMEDGROUPS, True):
# TODO: self.shownamedgroups()
pass
if settings.get(RESULTS_SHOWSAMPLE, True):
output.append("""<table cellpadding="0" cellspacing="0"><tr><td>
<b>Sample text matched against:</b>
</td></tr>
<tr><td bgcolor="#EEEEEE"><i>""")
output.append(self.htmlize(rawtext) or " ") # something must be in there, so if no raw text, at least force a space
output.append("""</i></td></tr></table>""")
self.MatchesWindow.SetPage("".join(output))
def htmlize(self, text):
"""Converts the text to html (escapes HTML entities and tags,
converts spaces to  's and enters to <br>'s."""
result = cgi.escape(text)
result = result.replace("\t", " ")
result = result.replace(" ", " ")
result = result.replace("\r\n", "<br />")
result = result.replace("\r", "<br />")
result = result.replace("\n", "<br />")
return result
def formatmatch(self, match, index, matchtemplate, starttemplate, endtemplate):
"""Pretty-prints a match as HTML, with colors for groups, etc."""
# first, make a dictionary of start and end positions
# (each char number in the match may be mapped to zero, one or more
# group numbers which start/end there)
# Groups function according to first-to-open, last-to-close.
starts, ends = {}, {}
# populate the dictionaries with empty lists
# A -1 key is necessary for groups which do not participate in the match.
for pos in range(-1, len(match.string)+1):
starts[pos], ends[pos] = [], []
# now populate them with real values: each position key will contain
# none or more group numbers
#print match.groups()
for groupnr in range(1+len(match.groups())):
#print groupnr
#print starts, ends
starts[match.start(groupnr)].append(groupnr)
ends[match.end(groupnr)].append(groupnr)
# prepare result
result = []
# now, loop through the string matched and build the layout
string = match.string
opengroups = [] # keeps track of open groups
for pos in range(match.start(), match.end()+1):
while 1:
# first, try to shut down any open groups
if opengroups and opengroups[-1] in ends[pos]: # if opengroups available and the last one must be closed now
# shut down open group and remove it from the opengroups list
result.append(endtemplate % {GROUPCOLOR: colors[opengroups[-1] % len(colors)],
GROUPNUMBER: opengroups.pop(-1)})
# secondly, try to open any new groups
elif starts[pos]: # if any new groups must be opened now
result.append(starttemplate % {GROUPCOLOR: colors[starts[pos][0] % len(colors)],
GROUPNUMBER: starts[pos][0]})
opengroups.append(starts[pos].pop(0))
else: # if no groups must be opened or closed, nothing special going on
if pos<match.end():
result.append(self.htmlize(string[pos]))
break # stop the while loop
result = "".join(result)
return matchtemplate % {MATCHINDEX: index,
FORMATTEDMATCH: result}
def showmatches(self):
"""Converts the results to html code and returns that.
Is not capable of handling an empty self.matches list of matches."""
if not self.matches:
raise ValueError, "self.matches must be non-empty list of re match opbjects"
index = -1 # number of current match that's being printed
html = []
html.append("""<table cellpadding="0" cellspacing="0"><tr><td bgcolor="#F8F8F8"><font color="#777777">""")
# load match layout templates
starttemplate = settings.get(STARTTEMPLATE, """<font color="#%%(%s)s"><b>(</b></font>""" % GROUPCOLOR)
endtemplate = settings.get(ENDTEMPLATE, """<font color="#%%(%s)s"><b>)<font size="0">%%(%s)s</font></b></font>""" % (GROUPCOLOR, GROUPNUMBER))
matchtemplate = settings.get(MATCHTEMPLATE, """<font color="#000000"><b><u><b><font size="0">%%(%s)s:</font></b></u>%%(%s)s</b></font>""" % (MATCHINDEX, FORMATTEDMATCH))
# loop through matches and create output
for match in self.matches:
index += 1
# determine what part of the string we're looking at
if index>0:
prevmatchend = self.matches[index-1].end()
else:
prevmatchend = 0
if index+1 < len(self.matches):
nextmatchstart = self.matches[index+1].start()
else:
nextmatchstart = -1
# append piece in between matches
html.append(self.htmlize(match.string[prevmatchend:match.start()]))
# append current match
#html.append(self.htmlize(match.string[match.start():match.end()]))
html.append(self.formatmatch(match, index, matchtemplate, starttemplate, endtemplate))
# append end piece if necessary
if index+1 >= len(self.matches): # if last match, print rest of string
html.append(self.htmlize(match.string[match.end():]))
html.append("""</font></td></tr></table>""")
res = "".join(html)
return res
def loadSettings(self):
"""Loads GUI settings from the settings system."""
# load some size settings
# set window size and position; make sure it's on screen
# and has a reasonable size
system = wx.SystemSettings_GetMetric
pos = list(settings.get(WINDOWPOSITION, (-1,-1)))
if pos[0]<-1: pos[0] = 0
if pos[1]<-1: pos[1] = 0
if pos[0]>system(wx.SYS_SCREEN_X)-50:
pos[0] = 0
if pos[1]>system(wx.SYS_SCREEN_Y)-50:
pos[1] = 0
self.SetPosition(pos)
size = list(settings.get(WINDOWSIZE, (-1, -1)))
if size[0]>system(wx.SYS_SCREEN_X):
size[0] = 640
if size[1]>system(wx.SYS_SCREEN_Y):
size[1] = 480
size[0] = max(size[0], 640)
size[1] = max(size[1], 480)
self.SetSize(size)
# load the sample text and regex last used
self.SampleText.SetValue(settings.get(SAMPLETEXT, ""))
self.RegexBox.SetValue(settings.get(REGEX, ""))
# load the flags and desired type of re functionality
for flag in self.flagmapper.keys():
self.flagmapper[flag].SetValue(settings.get(flag, False))
self.MethodBox.SetSelection(settings.get(SEARCHTYPE, 0))
# other settings
self.SplitterWindow.SetSashPosition(settings.get(SASHPOSITION, 100))
def saveSettings(self, dosave=True):
"""Puts all GUI settings in the settings system.
Arguments:
dosave -- if True, the save() method of Settings is called
when done
"""
# put all stuff that needs saving in the settings
settings.set(WINDOWSIZE, self.GetSize())
settings.set(WINDOWPOSITION, self.GetPosition())
settings.set(SASHPOSITION, self.SplitterWindow.GetSashPosition())
settings.set(SAMPLETEXT, self.SampleText.GetValue())
settings.set(REGEX, self.RegexBox.GetValue())
# save the selected flags
for flag in self.flagmapper.keys():
settings.set(flag, self.flagmapper[flag].GetValue())
settings.set(SEARCHTYPE, self.MethodBox.GetSelection())
if dosave: settings.save()
def close(self, event):
"""Prepares for shutdown and then closes the app."""
self.saveSettings()
# shut down the settings system
settings.shutdown()
# shut down the app
self.Destroy()
def speCreate(parent, info=None):
"""Integration of Kiki into spe (http://spe.pycs.net)"""
global settings
settings = Settings(dirname=".spe", filename="kikicfg.py", debugfile="kikidebug")
Kiki = MyFrameWithEvents(parent, -1, "")
Kiki.SetTitle(Kiki.GetTitle() + " - the ferret in your Spe")
if info and info.has_key('kikiPath'):
kikipath = info['kikiPath']
else:
kikipath = os.path.join(os.path.dirname(sys.argv[0]), "framework/contributions")
Kiki.icon(kikipath)
Kiki.Show(1)
return Kiki
def main():
global settings
settings = Settings(dirname=".kiki", filename="kikicfg.py", debugfile="kikidebug")
Kiki = wx.PySimpleApp()
wx.InitAllImageHandlers()
mw = MyFrameWithEvents(None, -1, "")
mw.icon()
Kiki.SetTopWindow(mw)
mw.Show(1)
Kiki.MainLoop()
if __name__ == "__main__":
main()
|