Styling in the wxPython2424 demo, a patch

Hi all,

I do not like too much the code styling in the wxPython demo.
- Monospaced fonts are better for Python indentation.
- Moving the caret between proportional chars fonts is difficult
  and the caret is not moving correcly in the begin of bolded chars.
- The original wxStyledTextCtrl_2.py is buggy.

I submit here a replacement of this file. "Boa" or "IDLE"
styling are proposed. "Boa" is the default.
You can also create your own styling. Tweak the code.

--> Robin.
I wanted to submit this "patch" when I downloaded wxPy 2.4.2.3,
but the 2.4.2.4 comes already two days after.
Congrats for the 2.4.2.4.

Jean-Michel Fauth, Switzerland

···

#================================================================
# wxNewSTC.py
# Py 2.3.0, wxPy 2.4.2.4
#
# This file may replace the file wxStyledTextCtrl_2.py of the wxPython
# 2.4.2.4 demo. Backup the original file and rename this one.
#
# - It uses monospaced fonts, python identation is important.
# - The stc does not like bold proportional fonts, the caret does not
# move properly.
# - The styles definition (definition order) in the original file
# was not ok.
# - This file contains two styling sets. The first corresponds
# more or less to the "Boa" styling. The second mimics "IDLE".
# Commnent/uncomment the code to select yout styling or implement
# your own styling in the # begin [user styling] ----- section.
# - Only tested on my win platform
# - Needs some more works, selection, margin widths, ...
#
# Jean-Michel Fauth, Switzerland
# 3 October 2003
#================================================================

from wxPython.wx import *
from wxPython.stc import *
import images
import keyword

#----------------------------------------------------------------------

demoText = """\
## This version of the editor has been set up to edit Python source
## code. Here is a copy of wxPython/demo/Main.py to play with.

"""

#----------------------------------------------------------------------

if wxPlatform == '__WXMSW__':
    faces = { 'times': 'Times New Roman',
              'mono' : 'Courier New', #'Lucida Console', 'Andale Mono'
              'helv' : 'Arial',
              'other': 'Comic Sans MS',
              'size' : 10,
              'size2': 8,
             }
else:
    faces = { 'times': 'Times',
              'mono' : 'Courier',
              'helv' : 'Helvetica',
              'other': 'new century schoolbook',
              'size' : 12,
              'size2': 10,
             }

#----------------------------------------------------------------------

class PythonSTC(wxStyledTextCtrl):
    
    def __init__(self, parent, ID):
        
        wxStyledTextCtrl.__init__(self, parent, ID,
                                  style = wxNO_FULL_REPAINT_ON_RESIZE)

        self.CmdKeyAssign(ord('B'), wxSTC_SCMOD_CTRL, wxSTC_CMD_ZOOMIN)
        self.CmdKeyAssign(ord('N'), wxSTC_SCMOD_CTRL, wxSTC_CMD_ZOOMOUT)

        self.SetLexer(wxSTC_LEX_PYTHON)
        self.SetKeyWords(0, " ".join(keyword.kwlist))

        self.SetProperty("fold", "1")
        self.SetProperty("tab.timmy.whinge.level", "1")
        self.SetMargins(0, 0)

        #self.SetViewWhiteSpace(True)
        #self.SetBufferedDraw(False)
        #self.SetViewEOL(True)
        #self.SetTwoPhaseDraw(False)
        #~ self.SetViewEOL(True)
        
        self.SetEdgeMode(wxSTC_EDGE_BACKGROUND)
        self.SetEdgeColumn(78)

        # Setup a margin to hold fold markers
        #self.SetFoldFlags(16) ### WHAT IS THIS VALUE? WHAT ARE THE OTHER FLAGS? DOES IT MATTER?
        self.SetMarginType(2, wxSTC_MARGIN_SYMBOL)
        self.SetMarginMask(2, wxSTC_MASK_FOLDERS)
        self.SetMarginSensitive(2, True)
        self.SetMarginWidth(2, 12)

        if 0: # simple folder marks, like the old version
            self.MarkerDefine(wxSTC_MARKNUM_FOLDER, wxSTC_MARK_ARROW, "navy", "navy")
            self.MarkerDefine(wxSTC_MARKNUM_FOLDEROPEN, wxSTC_MARK_ARROWDOWN, "navy", "navy")
            # Set these to an invisible mark
            self.MarkerDefine(wxSTC_MARKNUM_FOLDEROPENMID, wxSTC_MARK_BACKGROUND, "white", "black")
            self.MarkerDefine(wxSTC_MARKNUM_FOLDERMIDTAIL, wxSTC_MARK_BACKGROUND, "white", "black")
            self.MarkerDefine(wxSTC_MARKNUM_FOLDERSUB, wxSTC_MARK_BACKGROUND, "white", "black")
            self.MarkerDefine(wxSTC_MARKNUM_FOLDERTAIL, wxSTC_MARK_BACKGROUND, "white", "black")

        else: # more involved "outlining" folder marks
            self.MarkerDefine(wxSTC_MARKNUM_FOLDEREND, wxSTC_MARK_BOXPLUSCONNECTED, "white", "black")
            self.MarkerDefine(wxSTC_MARKNUM_FOLDEROPENMID, wxSTC_MARK_BOXMINUSCONNECTED, "white", "black")
            self.MarkerDefine(wxSTC_MARKNUM_FOLDERMIDTAIL, wxSTC_MARK_TCORNER, "white", "black")
            self.MarkerDefine(wxSTC_MARKNUM_FOLDERTAIL, wxSTC_MARK_LCORNER, "white", "black")
            self.MarkerDefine(wxSTC_MARKNUM_FOLDERSUB, wxSTC_MARK_VLINE, "white", "black")
            self.MarkerDefine(wxSTC_MARKNUM_FOLDER, wxSTC_MARK_BOXPLUS, "white", "black")
            self.MarkerDefine(wxSTC_MARKNUM_FOLDEROPEN, wxSTC_MARK_BOXMINUS, "white", "black")

        # register some images for use in the AutoComplete box.
        self.RegisterImage(1, images.getSmilesBitmap())
        self.RegisterImage(2, images.getFile1Bitmap())
        self.RegisterImage(3, images.getCopyBitmap())

# begin [original demo] -----------------------------------------------

        #~ self.SetCaretForeground("BLUE")

        # Make some styles, The lexer defines what each style is used for, we
        # just have to define what each style looks like. This set is adapted from
        # Scintilla sample property files.

        #~ self.StyleClearAll()

        #~ # Global default styles for all languages
        #~ self.StyleSetSpec(wxSTC_STYLE_DEFAULT, "face:%(helv)s,size:%(size)d" % faces)
        #~ self.StyleSetSpec(wxSTC_STYLE_LINENUMBER, "back:#C0C0C0,face:%(helv)s,size:%(size2)d" % faces)
        #~ self.StyleSetSpec(wxSTC_STYLE_CONTROLCHAR, "face:%(other)s" % faces)
        #~ self.StyleSetSpec(wxSTC_STYLE_BRACELIGHT, "fore:#FFFFFF,back:#0000FF,bold")
        #~ self.StyleSetSpec(wxSTC_STYLE_BRACEBAD, "fore:#000000,back:#FF0000,bold")

        #~ # Python styles
        #~ # Default
        #~ self.StyleSetSpec(wxSTC_P_DEFAULT, "fore:#000000,face:%(helv)s,size:%(size)d" % faces)
        #~ # Comments
        #~ self.StyleSetSpec(wxSTC_P_COMMENTLINE, "fore:#007F00,face:%(other)s,size:%(size)d" % faces)
        #~ # Number
        #~ self.StyleSetSpec(wxSTC_P_NUMBER, "fore:#007F7F,size:%(size)d" % faces)
        #~ # String
        #~ self.StyleSetSpec(wxSTC_P_STRING, "fore:#7F007F,face:%(helv)s,size:%(size)d" % faces)
        #~ # Single quoted string
        #~ self.StyleSetSpec(wxSTC_P_CHARACTER, "fore:#7F007F,face:%(helv)s,size:%(size)d" % faces)
        #~ # Keyword
        #~ self.StyleSetSpec(wxSTC_P_WORD, "fore:#00007F,bold,size:%(size)d" % faces)
        #~ # Triple quotes
        #~ self.StyleSetSpec(wxSTC_P_TRIPLE, "fore:#7F0000,size:%(size)d" % faces)
        #~ # Triple double quotes
        #~ self.StyleSetSpec(wxSTC_P_TRIPLEDOUBLE, "fore:#7F0000,size:%(size)d" % faces)
        #~ # Class name definition
        #~ self.StyleSetSpec(wxSTC_P_CLASSNAME, "fore:#0000FF,bold,underline,size:%(size)d" % faces)
        #~ # Function or method name definition
        #~ self.StyleSetSpec(wxSTC_P_DEFNAME, "fore:#007F7F,bold,size:%(size)d" % faces)
        #~ # Operators
        #~ self.StyleSetSpec(wxSTC_P_OPERATOR, "bold,size:%(size)d" % faces)
        #~ # Identifiers
        #~ self.StyleSetSpec(wxSTC_P_IDENTIFIER, "fore:#000000,face:%(helv)s,size:%(size)d" % faces)
        #~ # Comment-blocks
        #~ self.StyleSetSpec(wxSTC_P_COMMENTBLOCK, "fore:#7F7F7F,size:%(size)d" % faces)
        #~ # End of line where string is not closed
        #~ self.StyleSetSpec(wxSTC_P_STRINGEOL, "fore:#000000,face:%(mono)s,back:#E0C0E0,eol,size:%(size)d" % faces)

# begin [original demo] -----------------------------------------------

# begin [~boa styling] ------------------------------------------------
        
        #Colour of the caret
        self.SetCaretForeground("RED")
        #Colour of the selection
        self.SetSelBackground(True, "#88c4ff")
        self.SetSelForeground(True, "#000000")

        # Global default style for the stc 32
        self.StyleSetSpec(wxSTC_STYLE_DEFAULT, "face:%(mono)s,size:%(size)d" % faces)
        
        #Reset all styles to the defaullt defined above
        self.StyleClearAll()

        # Python styles
        # Default 0
        self.StyleSetSpec(wxSTC_P_DEFAULT, "fore:#000000,face:%(mono)s,size:%(size)d" % faces)
        # Comments 1
        self.StyleSetSpec(wxSTC_P_COMMENTLINE, "back:#e8ffe8,italic,fore:#007f00")
        # Number 2
        self.StyleSetSpec(wxSTC_P_NUMBER, "fore:#007f7f")
        # String 3
        self.StyleSetSpec(wxSTC_P_STRING, "fore:#7f007f")
        # Single quoted string 4
        self.StyleSetSpec(wxSTC_P_CHARACTER, "fore:#7f007f")
        # Keyword 5
        self.StyleSetSpec(wxSTC_P_WORD, "fore:#00007f,bold")
        # Triple quotes 6
        self.StyleSetSpec(wxSTC_P_TRIPLE, "fore:#000033")
        # Triple double quotes 7
        self.StyleSetSpec(wxSTC_P_TRIPLEDOUBLE, "fore:#000033,back:#ffffe8")
        # Class name definition 8
        self.StyleSetSpec(wxSTC_P_CLASSNAME, "fore:#0000ff,bold")
        # Function or method name definition 9
        self.StyleSetSpec(wxSTC_P_DEFNAME, "fore:#007f7f,bold")
        # Operators 10
        self.StyleSetSpec(wxSTC_P_OPERATOR, "bold")
        # Identifiers 11, default style is used
        #~ ## self.StyleSetSpec(wxSTC_P_IDENTIFIER, "xxxx")
        # Comment-blocks 12
        self.StyleSetSpec(wxSTC_P_COMMENTBLOCK, "fore:#7f7f7f,italic")
        # End of line where string is not closed 13
        self.StyleSetSpec(wxSTC_P_STRINGEOL, "fore:#000000,back:#e0c0e0,eolfilled")

        #Global stc styles, they styles must be defined here
        # Matching (, [, { 34
        self.StyleSetSpec(wxSTC_STYLE_BRACELIGHT, "fore:#0000ff,back:#ffff88,bold")
        # Non matching (, [, { 35
        self.StyleSetSpec(wxSTC_STYLE_BRACEBAD, "fore:#ff0000,back:#ffff88,bold")
        # Control chars 36, default style is used
        #~ ##self.StyleSetSpec(wxSTC_STYLE_CONTROLCHAR, "xxx")
        # Line number 33
        self.StyleSetSpec(wxSTC_STYLE_LINENUMBER, "back:#c0c0c0,face:%(helv)s,size:%(size2)d" % faces)

# end [~boa styling] ---------------------------------------------------

# begin [~idle styling] -------------------------------------------------

        #~ #Colour of the caret
        #~ self.SetCaretForeground("BLACK")
        #~ #Colour of the selection
        #~ self.SetSelBackground(True, "#0000a0")
        #~ self.SetSelForeground(True, "#ffffff")

        #~ # Global default style for the stc 32
        #~ self.StyleSetSpec(wxSTC_STYLE_DEFAULT, "face:%(mono)s,size:%(size)d" % faces)
        
        #Reset all styles to the defaullt defined above
        #~ self.StyleClearAll()

        #~ # Python styles
        #~ # Default 0
        #~ self.StyleSetSpec(wxSTC_P_DEFAULT, "fore:#000000,face:%(mono)s,size:%(size)d" % faces)
        #~ # Comments 1
        #~ self.StyleSetSpec(wxSTC_P_COMMENTLINE, "fore:#dd0000")
        #~ # String 3
        #~ self.StyleSetSpec(wxSTC_P_STRING, "fore:#00aa00")
        #~ # Single quoted string 4
        #~ self.StyleSetSpec(wxSTC_P_CHARACTER, "fore:#00aa00")
        #~ # Keyword 5
        #~ self.StyleSetSpec(wxSTC_P_WORD, "fore:#ff7700")
        #~ # Triple quotes 6
        #~ self.StyleSetSpec(wxSTC_P_TRIPLE, "fore:#00aa00")
        #~ # Triple double quotes 7
        #~ self.StyleSetSpec(wxSTC_P_TRIPLEDOUBLE, "fore:#00aa00")
        #~ # Class name definition 8
        #~ self.StyleSetSpec(wxSTC_P_CLASSNAME, "fore:#0000ff")
        #~ # Function or method name definition 9
        #~ self.StyleSetSpec(wxSTC_P_DEFNAME, "fore:#0000ff")
        #~ # Comment-blocks 12
        #~ self.StyleSetSpec(wxSTC_P_COMMENTBLOCK, "fore:#dd0000")

        #~ #Global stc styles, they styles must be defined here
        #~ # Matching (, [, { 34
        #~ self.StyleSetSpec(wxSTC_STYLE_BRACELIGHT, "fore:#0000ff,bold")
        #~ # Non matching (, [, { 35
        #~ self.StyleSetSpec(wxSTC_STYLE_BRACEBAD, "fore:#dd0000,bold")
        #~ # Line number 33
        #~ self.StyleSetSpec(wxSTC_STYLE_LINENUMBER, "back:#a0a0a0,face:%(helv)s,size:%(size2)d" % faces)

# end [~idle styling] -------------------------------------------------

# begin [user styling] -------------------------------------------------

        #define your style here
        
# end [user styling] -------------------------------------------------

        EVT_STC_UPDATEUI(self, ID, self.OnUpdateUI)
        EVT_STC_MARGINCLICK(self, ID, self.OnMarginClick)
        EVT_KEY_DOWN(self, self.OnKeyPressed)

    def OnKeyPressed(self, event):
        if self.CallTipActive():
            self.CallTipCancel()
        key = event.KeyCode()
        if key == 32 and event.ControlDown():
            pos = self.GetCurrentPos()
            # Tips
            if event.ShiftDown():
                self.CallTipSetBackground("yellow")
                self.CallTipShow(pos, 'lots of of text: blah, blah, blah\n\n'
                                 'show some suff, maybe parameters..\n\n'
                                 'fubar(param1, param2)')
            # Code completion
            else:
                #lst = []
                #for x in range(50000):
                # lst.append('%05d' % x)
                #st = " ".join(lst)
                #print len(st)
                #self.AutoCompShow(0, st)

                kw = keyword.kwlist[:]
                kw.append("zzzzzz?2")
                kw.append("aaaaa?2")
                kw.append("__init__?3")
                kw.append("zzaaaaa?2")
                kw.append("zzbaaaa?2")
                kw.append("this_is_a_longer_value")
                #kw.append("this_is_a_much_much_much_much_much_much_much_longer_value")

                kw.sort() # Python sorts are case sensitive
                self.AutoCompSetIgnoreCase(False) # so this needs to match

                # Images are specified with a appended "?type"
                for i in range(len(kw)):
                    if kw[i] in keyword.kwlist:
                        kw[i] = kw[i] + "?1"

                self.AutoCompShow(0, " ".join(kw))
        else:
            event.Skip()

    def OnUpdateUI(self, evt):
        # check for matching braces
        braceAtCaret = -1
        braceOpposite = -1
        charBefore = None
        caretPos = self.GetCurrentPos()
        if caretPos > 0:
            charBefore = self.GetCharAt(caretPos - 1)
            styleBefore = self.GetStyleAt(caretPos - 1)

        # check before
        if charBefore and chr(charBefore) in "[]{}()" and styleBefore == wxSTC_P_OPERATOR:
            braceAtCaret = caretPos - 1

        # check after
        if braceAtCaret < 0:
            charAfter = self.GetCharAt(caretPos)
            styleAfter = self.GetStyleAt(caretPos)
            if charAfter and chr(charAfter) in "[]{}()" and styleAfter == wxSTC_P_OPERATOR:
                braceAtCaret = caretPos

        if braceAtCaret >= 0:
            braceOpposite = self.BraceMatch(braceAtCaret)

        if braceAtCaret != -1 and braceOpposite == -1:
            self.BraceBadLight(braceAtCaret)
        else:
            self.BraceHighlight(braceAtCaret, braceOpposite)
            #pt = self.PointFromPosition(braceOpposite)
            #self.Refresh(True, wxRect(pt.x, pt.y, 5,5))
            #print pt
            #self.Refresh(False)

    def OnMarginClick(self, evt):
        # fold and unfold as needed
        if evt.GetMargin() == 2:
            if evt.GetShift() and evt.GetControl():
                self.FoldAll()
            else:
                lineClicked = self.LineFromPosition(evt.GetPosition())
                if self.GetFoldLevel(lineClicked) & wxSTC_FOLDLEVELHEADERFLAG:
                    if evt.GetShift():
                        self.SetFoldExpanded(lineClicked, True)
                        self.Expand(lineClicked, True, True, 1)
                    elif evt.GetControl():
                        if self.GetFoldExpanded(lineClicked):
                            self.SetFoldExpanded(lineClicked, False)
                            self.Expand(lineClicked, False, True, 0)
                        else:
                            self.SetFoldExpanded(lineClicked, True)
                            self.Expand(lineClicked, True, True, 100)
                    else:
                        self.ToggleFold(lineClicked)

    def FoldAll(self):
        lineCount = self.GetLineCount()
        expanding = True

        # find out if we are folding or unfolding
        for lineNum in range(lineCount):
            if self.GetFoldLevel(lineNum) & wxSTC_FOLDLEVELHEADERFLAG:
                expanding = not self.GetFoldExpanded(lineNum)
                break;

        lineNum = 0
        while lineNum < lineCount:
            level = self.GetFoldLevel(lineNum)
            if level & wxSTC_FOLDLEVELHEADERFLAG and \
               (level & wxSTC_FOLDLEVELNUMBERMASK) == wxSTC_FOLDLEVELBASE:

                if expanding:
                    self.SetFoldExpanded(lineNum, True)
                    lineNum = self.Expand(lineNum, True)
                    lineNum = lineNum - 1
                else:
                    lastChild = self.GetLastChild(lineNum, -1)
                    self.SetFoldExpanded(lineNum, False)
                    if lastChild > lineNum:
                        self.HideLines(lineNum+1, lastChild)

            lineNum = lineNum + 1

    def Expand(self, line, doExpand, force=False, visLevels=0, level=-1):
        lastChild = self.GetLastChild(line, level)
        line = line + 1
        while line <= lastChild:
            if force:
                if visLevels > 0:
                    self.ShowLines(line, line)
                else:
                    self.HideLines(line, line)
            else:
                if doExpand:
                    self.ShowLines(line, line)

            if level == -1:
                level = self.GetFoldLevel(line)

            if level & wxSTC_FOLDLEVELHEADERFLAG:
                if force:
                    if visLevels > 1:
                        self.SetFoldExpanded(line, True)
                    else:
                        self.SetFoldExpanded(line, False)
                    line = self.Expand(line, doExpand, force, visLevels-1)

                else:
                    if doExpand and self.GetFoldExpanded(line):
                        line = self.Expand(line, True, force, visLevels-1)
                    else:
                        line = self.Expand(line, False, force, visLevels-1)
            else:
                line = line + 1;

        return line

#----------------------------------------------------------------------

_USE_PANEL = 1

def runTest(frame, nb, log):
    if not _USE_PANEL:
        ed = p = PythonSTC(nb, -1)
    else:
        p = wxPanel(nb, -1, style = wxNO_FULL_REPAINT_ON_RESIZE)
        ed = PythonSTC(p, -1)
        s = wxBoxSizer(wxHORIZONTAL)
        s.Add(ed, 1, wxEXPAND)
        p.SetSizer(s)
        p.SetAutoLayout(True)

    ed.SetText(demoText + open('Main.py').read())
    ed.EmptyUndoBuffer()
    ed.Colourise(0, -1)

    # line numbers in the margin
    ed.SetMarginType(1, wxSTC_MARGIN_NUMBER)
    ed.SetMarginWidth(1, 25)

    return p

#----------------------------------------------------------------------

overview = """\
<html><body>
Once again, no docs yet. <b>Sorry.</b> But <a href="data/stc.h.html">this</a>
and <a href="http://www.scintilla.org/ScintillaDoc.html">this</a> should
be helpful.
</body><html>
"""

if __name__ == '__main__':
    import sys,os
    import run
    run.main(['', os.path.basename(sys.argv[0])])

#eof-------------------------------------------------------------------

Jean-Michel Fauth wrote:

Hi all,

I do not like too much the code styling in the wxPython demo.
- Monospaced fonts are better for Python indentation.
- Moving the caret between proportional chars fonts is difficult
  and the caret is not moving correcly in the begin of bolded chars.
- The original wxStyledTextCtrl_2.py is buggy.

I submit here a replacement of this file. "Boa" or "IDLE"
styling are proposed. "Boa" is the default. You can also create your own styling. Tweak the code.

Did you change anything besides the style settings? (If you had sent a patch as prefered instead of the whole file I wouldn't have to ask that! :wink: )

--> Robin. I wanted to submit this "patch" when I downloaded wxPy 2.4.2.3,
but the 2.4.2.4 comes already two days after.

2.4.2.3 was one of the prerelease iterations used for release testing. When I get in that mode new builds can come every day or two as the final little nasties get ironed out.

···

--
Robin Dunn
Software Craftsman
http://wxPython.org Java give you jitters? Relax with wxPython!

Jean-Michel Fauth:

I do not like too much the code styling in the wxPython demo.
- Monospaced fonts are better for Python indentation.

   The indentation white space is styled in the wxSTC_P_DEFAULT style so the
size can be changed without changing the fonts for other elements.

   Neil

Did you change anything besides the style settings? (If you had sent a
patch as prefered instead of the whole file I wouldn't have to ask that!
:wink: )

Allow me to suggest Scooter Software - Home of Beyond Compare for such
situations. :wink:

Well, there's some people that stick to good old diffs and don't use
any M$ Software in development :slight_smile:

> Did you change anything besides the style settings? (If you had sent a
> patch as prefered instead of the whole file I wouldn't have to ask that!
> :wink: )

Allow me to suggest Scooter Software - Home of Beyond Compare for such
situations. :wink:

---------------------------------------------------------------------
To unsubscribe, e-mail: wxPython-users-unsubscribe@lists.wxwindows.org
For additional commands, e-mail: wxPython-users-help@lists.wxwindows.org

- --
  UC

- --
Open Source Solutions 4U, LLC 2570 Fleetwood Drive
Phone: +1 650 872 2425 San Bruno, CA 94066
Cell: +1 650 302 2405 United States
Fax: +1 650 872 2417

···

On Saturday 04 October 2003 12:45 am, Jeff Grimmett wrote:

For those who want GUI diff tools, there are (at least) two GPL ones:

http://xxdiff.sourceforge.net/ (*nix)
http://WinMerge.sourceforge.net/ (Windows)

Cheers,

Rasjid.

- --
Rasjid Wilcox
Canberra, Australia (UTC +10 hrs)
http://www.openminddev.net

···

On Saturday 04 October 2003 17:45, Jeff Grimmett wrote:

> Did you change anything besides the style settings? (If you had sent a
> patch as prefered instead of the whole file I wouldn't have to ask that!
> :wink: )

Allow me to suggest Scooter Software - Home of Beyond Compare for such
situations. :wink:

> Allow me to suggest Scooter Software - Home of Beyond Compare for such
> situations. :wink:

Well, there's some people that stick to good old diffs and don't use
any M$ Software in development :slight_smile:

Yeah, I know it's a glorified Diff, but that was the link I had and I am, of
course, basically a lazy bastige at heart :slight_smile: