#@+leo-ver=4-thin
#@+node:ekr.20031218072017.329:@thin ../doc/leoNotes.txt
#@@nocolor

This contains my notes for the Leo project.

#@+all
#@+node:ekr.20031218072017.365:How to...
#@+node:ekr.20031218072017.366:How to add and remove files from CVS repository
use the command line option in the admin menu to do the following:

add leoConfig.py and leoConfig.txt
	cvs add leoConfig.txt
	cvs add leoConfig.py
	(then do commit)

remove readme*.doc
	remove files from working area (done)
	cvs remove readme1.doc
	cvs remove readme2.doc
	...
	(then do commit)
#@nonl
#@-node:ekr.20031218072017.366:How to add and remove files from CVS repository
#@+node:ekr.20031218072017.384:How to export syntax colored code preserving colors
Scite has the option to "Export as html" and "export as rtf", and it will be
full of colour and fonts - and you can define them in properties, so it will be
the same as during editing.
#@nonl
#@-node:ekr.20031218072017.384:How to export syntax colored code preserving colors
#@+node:ekr.20031218072017.385:How to Increase environment space
To increase the size of environment space, add the following to config.sys:

shell=C:\windows\command\command.com /p:4096

Notes:

1. The path C:\windows\command\command.com may vary.
Check you system for the location of command.com.

2. This works for versions of Windows prior to Me.
On Me you set the registry somehow.
No information on XP.
#@nonl
#@-node:ekr.20031218072017.385:How to Increase environment space
#@+node:ekr.20031218072017.386:How to remove cursed newlines: use binary mode
teknico ( Nicola Larosa ) 
 RE: Removing '\r' characters?   
2002-09-16 14:27  
> I am plowing through old bug reports, and I found the following, from whom 
> I don't know: 

That's from me, *again*. You are kindly advised to stop forgetting the attribution to all my bug reports. ;^) 

>> - Source files still have the dreaded \r in them. Why don't you switch 
>> to \n only, once and for all, and live happily ever after? ;^) 

> I sure whould like to do that, and I'm not sure how to do this. All 
> versions of the read code attempt to remove '\r' characters, and all 
> versions of the write code write '\n' only for newlines. 

Sorry for being a bit vague, I was talking about the Leo source files themselves. I don't know what you use to edit them, ;^))) but in version 3.6 they still have \r\n as end-of-line. 

If Leo itself does not solve the problem, may I suggest the 
Tools/scripts/crlf.py script in the Python source distibution? It's nice and simple, and skips binary files, too. That's what I use every time I install a new version of Leo. :^) 
 
#@+node:ekr.20031218072017.387:The solution
Under unix, python writes "\n" as "\n"; under windows, it writes it as "\r\n". The unix python interpreter ignores trailing "\r" in python source files. There are no such guarantees for other languages. Unix users should be able to get rid of the cosmetically detrimental "\r" either by running dos2unix on the offending files, or, if they're part of a .leo project, reading them into leo and writing them out again.  


By: edream ( Edward K. Ream ) 
 RE: Removing '\r' characters?   
2002-09-17 09:34  
Oh, I see. Thanks very much for this clarification. 

Just to make sure I understand you: the problem with '\r' characters is that: 

1. I am creating LeoPy.leo and LeoDocs.leo on Windows and 
2. People are then using these files on Linux. 

and the way to remove the '\r' characters: 

1. I could run dos2unix on all distributed files just before committing to CVS or making a final distribution or 
2. People could, say, do the following: 

Step 1: Read and Save the .leo files, thereby eliminating the '\r' in those files and 
Step 2: Use the Write @file nodes command on all derived files to clear the '\r' in those files. 

Do you agree so far? 

> Under unix, python writes "\n" as "\n"; under windows, it writes it as "\r\n". 

I am going to see if there is any way to get Python to write a "raw" '\n' to a file. I think there must be. This would solve the problem once and for all. 

Thanks again for this most helpful comment. 

Edward
#@nonl
#@-node:ekr.20031218072017.387:The solution
#@+node:ekr.20031218072017.388:cursed newline answer
In 2.3 you can open files with the "U" flag and get "universal newline"
support: 

% python
Python 2.3a0 (#86, Sep 4 2002, 21:13:00) 
[GCC 2.96 20000731 (Mandrake Linux 8.1 2.96-0.62mdk)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> f = open("crlf.txt")
>>> line = f.readline()
>>> line
'This is an example of what I have come to call the "cursed newline"
problem,\r\n'
>>> f = open("crlf.txt", "rU")
>>> line = f.readline()
>>> line
'This is an example of what I have come to call the "cursed newline" problem,\n'

#@-node:ekr.20031218072017.388:cursed newline answer
#@+node:ekr.20031218072017.389:cursed newline answer 2
> You can open the file in 'binary' mode (adding 'b' to the mode string) and
> the file will contain '\r\n' on both platforms (and any other platforms.)

Nope. Exactly wrong. In 2.2 and those before, when files are opened in
*text* mode (no "b") then reading them will provide Unix-style line endings
(newline only). When you open files in binary mode then you see the bytes
stored in the file.

On Unix systems there's no difference in the contents of a file whether in
binary or text mode. On Windows a file is shorter by the number of carriage
returns. On the Mac I have no idea what they do. Probably just carriage
returns, to be different :-)

2.3 will be a bit more flexible about such mattrers.
#@-node:ekr.20031218072017.389:cursed newline answer 2
#@-node:ekr.20031218072017.386:How to remove cursed newlines: use binary mode
#@+node:ekr.20031218072017.390:How to run Pychecker
import pychecker.checker ; import leo
#@nonl
#@-node:ekr.20031218072017.390:How to run Pychecker
#@+node:ekr.20031218072017.391:How to use CVS branches
@nocolor

I have a fair bit of expertise on CVS branches. It's late at night, so I don't have time for a long soapbox spiel at the moment. I will try to post something tomorrow. 

The brief picture is: 

* Check out code from CVS at the point you want to create the branch. 

* Make sure none of the files in your sandbox is modified. 

* Create the branch (cvs tag -b branchname). The branch name must start with a letter (upper or lower case) and thereafter can have alphanumeric characters, hyphens, and underscores (no periods or spaces). 

* The branch is created on the repository, but your sandbox is still checked out on the main branch. To check out on the new branch, do "cvs up -r branchname". 

When you want to merge changes back into the main branch, you can use "cvs up -r MAIN" to retrieve the main branch, then "cvs up -j branchname" to merge changes, then "cvs commit" to commit the merged version to the main branch AFTER YOU HAVE VERIFIED IT. 

I would recommend caution with merging because as you have noted, leo files are not well set up for CVS. They don't merge well because of inconsistent sentinel values. 

You may want to look at manually merging changes back into the main branch until leo implements invariant unique (UUID) sentinel indices. 

This will not hurt your ability to use branches, only your ability to automatically merge changes from one branch onto another.
#@nonl
#@-node:ekr.20031218072017.391:How to use CVS branches
#@+node:ekr.20031218072017.392:Python Notes & HowTo's...
#@+node:ekr.20031218072017.393:What's new for each version:
New in 2.2 (Do not use)

- Iterators/Generators
- Nested Scopes
- New Classes

The what's new for each version:

http://www.amk.ca/python/2.0/
http://www.amk.ca/python/2.1/
#@+node:ekr.20031218072017.394:@url http://www.python.org/2.3/highlights.html
#@-node:ekr.20031218072017.394:@url http://www.python.org/2.3/highlights.html
#@+node:ekr.20031218072017.395:@url http://www.amk.ca/python/2.1/
#@-node:ekr.20031218072017.395:@url http://www.amk.ca/python/2.1/
#@+node:ekr.20031218072017.396:@url http://www.amk.ca/python/2.0/
#@-node:ekr.20031218072017.396:@url http://www.amk.ca/python/2.0/
#@-node:ekr.20031218072017.393:What's new for each version:
#@+node:ekr.20031218072017.397:Default values & keyword arguments
@nocolor

1. You specify default values of _formal parameters_ in a def statement.

2. You specify keywords arguments in a _function call_.

3. An argument list must have any positional arguments followed by any keyword arguments, where the keywords must be chosen from the formal parameter names.  It's not important whether a formal parameter has a default value or not.

4. No argument may receive a value more than once.

5. When a final formal parameter of the form **name is present, it receives a dictionary containing all keyword arguments whose keyword doesn't correspond to a formal parameter.

EKR Notes:

1.  I have been confusing default values with keyword arguments.  _Any_ formal parameter may be specified with a keyword argument!

2.  Arbitrary keyword params can be used if the def has an **arg.
#@nonl
#@-node:ekr.20031218072017.397:Default values & keyword arguments
#@+node:ekr.20031218072017.398:How to call any Python method from the C API
In general, everything you can do in Python is accessible through the C API.

	lines = block.split('\n');
 
> That will be
 
	lines = PyObject_CallMethod(block, "split", "s", "\n");
#@-node:ekr.20031218072017.398:How to call any Python method from the C API
#@+node:ekr.20031218072017.399:How to run Python programs easily on NT,2K,XP
#@+node:ekr.20031218072017.400:setting the PATHEXT env var
It is worth noting that NT, Win2K and XP all have an alternative which is
to add .PY to the PATHEXT environment variable. Then you can run any .PY
file directly just by typing the name of the script without the extension. 

e.g.
C:\>set PATHEXT=.COM;.EXE;.BAT;.CMD

C:\>set PATH=%PATH%;c:\python22\tools\Scripts

C:\>google
'google' is not recognized as an internal or external command,
operable program or batch file.

C:\>set PATHEXT=.COM;.EXE;.BAT;.CMD;.PY

C:\>google
Usage: C:\python22\tools\Scripts\google.py querystring

C:\>
#@-node:ekr.20031218072017.400:setting the PATHEXT env var
#@+node:ekr.20031218072017.401:Yet another Python .bat wrapper
>> It has a header of just one line. All the ugly stuff is at the end.
>>
>> -------------------------------------------------------------------
>> goto ="python"
>>
>> # Python code goes here
>>
>> ''' hybrid python/batch footer:
>> @:="python"
>> @python.exe %0 %1 %2 %3 %4 %5 %6 %7 %8 %9
>> @if errorlevel 9009 echo Python may be downloaded from
>www.python.org/download
>> @rem '''
>> -------------------------------------------------------------------
>>
>>         Oren
>>
>

It's for running python scripts on windows, without having to type:

[<path to python>\]python[.exe] <scriptname> [<arguments>*]

and almost takes the place of the "shabang" line at the top of *nix
scripts.

#@-node:ekr.20031218072017.401:Yet another Python .bat wrapper
#@-node:ekr.20031218072017.399:How to run Python programs easily on NT,2K,XP
#@-node:ekr.20031218072017.392:Python Notes & HowTo's...
#@+node:ekr.20031218072017.367:How to add support for a new language
@nocolor

- Add a new entries in << define global data structures >> app

- Add a new Tk.Radiobutton in <<create the Target Language frame>>

- Add an entry to the languages list in <<configure language-specific settings>>

- Add a list of the keywords of the language to << define colorizer keywords >>

  N.B.: the name of this list must be x_keywords, where x is the entry in language in step a.

- Add any language-specifig code to leoColor.colorizeAnyLanguage.
  For most languages nothing need be done in this step.

TESTS

- Test the syntax coloring for the new language by using the @language directive.

- Test workings of the Preferences Panel by choosing the language in the panel and by looking at code that is _not_ under control of an @language directive.

- Test the leoConfig.txt by setting default_target_language to the name of the new language.  When you restart Leo, the new language should be selected in the Prefs panel.

- Remove leoConfig.txt, select the new language in the Prefs panel, and save the .leo file.  Open the file with a text editor and check to make sure that the <preferences> tag (near the top) contains an entry like this:

<preferences allow_rich_text="0" defaultTargetLanguage="Python">
</preferences>

but with the name of your new language instead of "Python".

- Create an @root node and verify that you can Tangle it.

@color
#@nonl
#@+node:ekr.20031218072017.368:<< define global data structures >> app
# Internally, lower case is used for all language names.
self.language_delims_dict = {
    "actionscript" : "// /* */", #jason 2003-07-03
    "c" : "// /* */", # C, C++ or objective C.
    "csharp" : "// /* */",	# C#
    "css" : "/* */", # 4/1/04
    "cweb" : "@q@ @>", # Use the "cweb hack"
    "elisp" : ";",
    "forth" : "_\\_ _(_ _)_", # Use the "REM hack"
    "fortran" : "C",
    "fortran90" : "!",
    "html" : "<!-- -->",
    "java" : "// /* */",
    "latex" : "%",
    "pascal" : "// { }",
    "perl" : "#",
    "perlpod" : "# __=pod__ __=cut__", # 9/25/02: The perlpod hack.
    "php" : "//",
    "plain" : "#", # We must pick something.
    "python" : "#",
    "rapidq" : "'", # fil 2004-march-11
    "rebol" : ";",  # jason 2003-07-03
    "shell" : "#",  # shell scripts
    "tcltk" : "#",
    "unknown" : "#" } # Set when @comment is seen.

self.language_extension_dict = {
    "actionscript" : "as", #jason 2003-07-03
    "c" : "c",
    "css" : "css", # 4/1/04
    "cweb" : "w",
    "elisp" : "el",
    "forth" : "forth",
    "fortran" : "f",
    "fortran90" : "f",
    "html" : "html",
    "java" : "java",
    "latex" : "tex", # 1/8/04
    "noweb" : "nw",
    "pascal" : "p",
    "perl" : "perl",
    "perlpod" : "perl",
    "php" : "php",
    "plain" : "txt",
    "python" : "py",
    "rapidq" : "bas", # fil 2004-march-11
    "rebol" : "r",    # jason 2003-07-03
    "shell" : "sh",   # DS 4/1/04
    "tex" : "tex",
    "tcltk" : "tcl",
    "unknown" : "txt" } # Set when @comment is seen.
    
self.extension_dict = {
    "as"    : "actionscript",
    "bas"   : "rapidq",
    "c"     : "c",
    "css"   : "css",
    "el"    : "elisp",
    "forth" : "forth",
    "f"     : "fortran90", # or fortran ?
    "html"  : "html",
    "java"  : "java",
    "noweb" : "nw",
    "p"     : "pascal",
    "perl"  : "perl",
    "php"   : "php",
    "py"    : "python",
    "r"     : "rebol",
    "sh"    : "shell",
    "tex"   : "tex",
    "txt"   : "plain",
    "tcl"   : "tcltk",
    "w"     : "cweb" }
#@-node:ekr.20031218072017.368:<< define global data structures >> app
#@+node:ekr.20031218072017.369:<< Create the Target Language frame >> frame
# Frame and title
w,target = gui.create_labeled_frame (outer,caption="Default Target Language")
w.pack(padx=2,pady=2,expand=1,fill="x")

# Frames for two columns of radio buttons
lt = Tk.Frame(target)
rt = Tk.Frame(target)
lt.pack(side="left")
rt.pack(side="right")

# Left column of radio buttons.
left_data = [
    ("ActionScript", "actionscript"),
    ("C#",    "csharp"),
    ("C/C++", "c"),
    ("CSS",   "css"),
    ("CWEB",  "cweb"),
    ("elisp", "elisp"),
    ("HTML",  "html"),
    ("Java",  "java"),
    ("LaTeX", "latex"),
    ("Pascal","pascal")]

for text,value in left_data:
    button = Tk.Radiobutton(lt,anchor="w",text=text,
        variable=self.lang_var,value=value,command=self.set_lang)
    button.pack(fill="x")

# Right column of radio buttons.
right_data = [
    ("Perl", "perl"),
    ("Perl+POD",   "perlpod"),
    ("PHP",        "php"),
    ("Plain Text", "plain"),
    ("Python",     "python"),
    ("RapidQ",     "rapidq"),
    ("Rebol",      "rebol"),
    ("Shell",      "shell"),
    ("tcl/tk",     "tcltk")]

for text,value in right_data:
    button = Tk.Radiobutton(rt,anchor="w",text=text,
        variable=self.lang_var,value=value,command=self.set_lang)
    button.pack(fill="x")
#@nonl
#@-node:ekr.20031218072017.369:<< Create the Target Language frame >> frame
#@+node:ekr.20031218072017.370:<< configure language-specific settings >> colorizer
# Define has_string, keywords, single_comment_start, block_comment_start, block_comment_end.

if self.language == "cweb": # Use C comments, not cweb sentinel comments.
    delim1,delim2,delim3 = g.set_delims_from_language("c")
elif self.comment_string:
    delim1,delim2,delim3 = g.set_delims_from_string(self.comment_string)
elif self.language == "plain": # 1/30/03
    delim1,delim2,delim3 = None,None,None
else:
    delim1,delim2,delim3 = g.set_delims_from_language(self.language)

self.single_comment_start = delim1
self.block_comment_start = delim2
self.block_comment_end = delim3

# A strong case can be made for making this code as fast as possible.
# Whether this is compatible with general language descriptions remains to be seen.
self.case_sensitiveLanguage = self.language not in case_insensitiveLanguages
self.has_string = self.language != "plain"
if self.language == "plain":
    self.string_delims = ()
elif self.language in ("elisp","html"):
    self.string_delims = ('"')
else:
    self.string_delims = ("'",'"')
self.has_pp_directives = self.language in ("c","csharp","cweb","latex")

# The list of languages for which keywords exist.
# Eventually we might just use language_delims_dict.keys()
languages = [
    "actionscript","c","csharp","css","cweb","elisp","html","java","latex",
    "pascal","perl","perlpod","php","python","rapidq","rebol","shell","tcltk"]

self.keywords = []
if self.language == "cweb":
    for i in self.c_keywords:
        self.keywords.append(i)
    for i in self.cweb_keywords:
        self.keywords.append(i)
else:
    for name in languages:
        if self.language==name: 
            # g.trace("setting keywords for",name)
            self.keywords = getattr(self, name + "_keywords")

# Color plain text unless we are under the control of @nocolor.
# state = g.choose(self.flag,"normal","nocolor")
state = self.setFirstLineState()

if 1: # 10/25/02: we color both kinds of references in cweb mode.
    self.lb = "<<"
    self.rb = ">>"
else:
    self.lb = g.choose(self.language == "cweb","@<","<<")
    self.rb = g.choose(self.language == "cweb","@>",">>")
#@nonl
#@-node:ekr.20031218072017.370:<< configure language-specific settings >> colorizer
#@+node:ekr.20031218072017.371:<< define colorizer keywords >> colorizer
@others

cweb_keywords = c_keywords
perlpod_keywords = perl_keywords
#@nonl
#@+node:ekr.20031218072017.372:actionscript keywords
actionscript_keywords = [
#Jason 2003-07-03 
#Actionscript keywords for Leo adapted from UltraEdit syntax highlighting
"break", "call", "continue", "delete", "do", "else", "false", "for", "function", "goto", "if", "in", "new", "null", "return", "true", "typeof", "undefined", "var", "void", "while", "with", "#include", "catch", "constructor", "prototype", "this", "try", "_parent", "_root", "__proto__", "ASnative", "abs", "acos", "appendChild", "asfunction", "asin", "atan", "atan2", "attachMovie", "attachSound", "attributes", "BACKSPACE", "CAPSLOCK", "CONTROL", "ceil", "charAt", "charCodeAt", "childNodes", "chr", "cloneNode", "close", "concat", "connect", "cos", "createElement", "createTextNode", "DELETEKEY", "DOWN", "docTypeDecl", "duplicateMovieClip", "END", "ENTER", "ESCAPE", "enterFrame", "entry", "equal", "eval", "evaluate", "exp", "firstChild", "floor", "fromCharCode", "fscommand", "getAscii", "getBeginIndex", "getBounds", "getBytesLoaded", "getBytesTotal", "getCaretIndex", "getCode", "getDate", "getDay", "getEndIndex", "getFocus", "getFullYear", "getHours", "getMilliseconds", "getMinutes", "getMonth", "getPan", "getProperty", "getRGB", "getSeconds", "getTime", "getTimer", "getTimezoneOffset", "getTransform", "getURL", "getUTCDate", "getUTCDay", "getUTCFullYear", "getUTCHours", "getUTCMilliseconds", "getUTCMinutes", "getUTCMonth", "getUTCSeconds", "getVersion", "getVolume", "getYear", "globalToLocal", "gotoAndPlay", "gotoAndStop", "HOME", "haschildNodes", "hide", "hitTest", "INSERT", "Infinity", "ifFrameLoaded", "ignoreWhite", "indexOf", "insertBefore", "int", "isDown", "isFinite", "isNaN", "isToggled", "join", "keycode", "keyDown", "keyUp", "LEFT", "LN10", "LN2", "LOG10E", "LOG2E", "lastChild", "lastIndexOf", "length", "load", "loaded", "loadMovie", "loadMovieNum", "loadVariables", "loadVariablesNum", "localToGlobal", "log", "MAX_VALUE", "MIN_VALUE", "max", "maxscroll", "mbchr", "mblength", "mbord", "mbsubstring", "min", "NEGATIVE_INFINITY", "NaN", "newline", "nextFrame", "nextScene", "nextSibling", "nodeName", "nodeType", "nodeValue", "on", "onClipEvent", "onClose", "onConnect", "onData", "onLoad", "onXML", "ord", "PGDN", "PGUP", "PI", "POSITIVE_INFINITY", "parentNode", "parseFloat", "parseInt", "parseXML", "play", "pop", "pow", "press", "prevFrame", "previousSibling", "prevScene", "print", "printAsBitmap", "printAsBitmapNum", "printNum", "push", "RIGHT", "random", "release", "removeMovieClip", "removeNode", "reverse", "round", "SPACE", "SQRT1_2", "SQRT2", "scroll", "send", "sendAndLoad", "set", "setDate", "setFocus", "setFullYear", "setHours", "setMilliseconds", "setMinutes", "setMonth", "setPan", "setProperty", "setRGB", "setSeconds", "setSelection", "setTime", "setTransform", "setUTCDate", "setUTCFullYear", "setUTCHours", "setUTCMilliseconds", "setUTCMinutes", "setUTCMonth", "setUTCSeconds", "setVolume", "setYear", "shift", "show", "sin", "slice", "sort", "start", "startDrag", "status", "stop", "stopAllSounds", "stopDrag", "substr", "substring", "swapDepths", "splice", "split", "sqrt", "TAB", "tan", "targetPath", "tellTarget", "toggleHighQuality", "toLowerCase", "toString", "toUpperCase", "trace", "UP", "UTC", "unescape", "unloadMovie", "unLoadMovieNum", "unshift", "updateAfterEvent", "valueOf", "xmlDecl", "_alpha", "_currentframe", "_droptarget", "_focusrect", "_framesloaded", "_height", "_highquality", "_name", "_quality", "_rotation", "_soundbuftime", "_target", "_totalframes", "_url", "_visible", "_width", "_x", "_xmouse", "_xscale", "_y", "_ymouse", "_yscale", "and", "add", "eq", "ge", "gt", "le", "lt", "ne", "not", "or", "Array", "Boolean", "Color", "Date", "Key", "Math", "MovieClip", "Mouse", "Number", "Object", "Selection", "Sound", "String", "XML", "XMLSocket"
]
#@nonl
#@-node:ekr.20031218072017.372:actionscript keywords
#@+node:ekr.20040206072057:c# keywords
csharp_keywords = [
    "abstract","as",
    "base","bool","break","byte",
    "case","catch","char","checked","class","const","continue",
    "decimal","default","delegate","do","double",
    "else","enum","event","explicit","extern",
    "false","finally","fixed","float","for","foreach",
    "get","goto",
    "if","implicit","in","int","interface","internal","is",
    "lock","long",
    "namespace","new","null",
    "object","operator","out","override",
    "params","partial","private","protected","public",
    "readonly","ref","return",
    "sbyte","sealed","set","short","sizeof","stackalloc",
    "static","string","struct","switch",
    "this","throw","true","try","typeof",
    "uint","ulong","unchecked","unsafe","ushort","using",
    "value","virtual","void","volatile",
    "where","while",
    "yield"]
#@nonl
#@-node:ekr.20040206072057:c# keywords
#@+node:ekr.20031218072017.373:c/c++ keywords
c_keywords = [
    # C keywords
    "auto","break","case","char","continue",
    "default","do","double","else","enum","extern",
    "float","for","goto","if","int","long","register","return",
    "short","signed","sizeof","static","struct","switch",
    "typedef","union","unsigned","void","volatile","while",
    # C++ keywords
    "asm","bool","catch","class","const","const_cast",
    "delete","dynamic_cast","explicit","false","friend",
    "inline","mutable","namespace","new","operator",
    "private","protected","public","reinterpret_cast","static_cast",
    "template","this","throw","true","try",
    "typeid","typename","using","virtual","wchar_t"]
#@nonl
#@-node:ekr.20031218072017.373:c/c++ keywords
#@+node:ekr.20040401103539:css keywords
css_keywords = [
#html tags
"address", "applet", "area", "a", "base", "basefont",
"big", "blockquote", "body", "br", "b", "caption", "center",
"cite", "code", "dd", "dfn", "dir", "div", "dl", "dt", "em", "font",
"form", "h1", "h2", "h3", "h4", "h5", "h6", "head", "hr", "html", "img",
"input", "isindex", "i", "kbd", "link", "li", "link", "map", "menu",
"meta", "ol", "option", "param", "pre", "p", "samp",
"select", "small", "span", "strike", "strong", "style", "sub", "sup",
"table", "td", "textarea", "th", "title", "tr", "tt", "ul", "u", "var",
#units
"mm", "cm", "in", "pt", "pc", "em", "ex", "px",
#colors
"aqua", "black", "blue", "fuchsia", "gray", "green", "lime", "maroon", "navy", "olive", "purple", "red", "silver", "teal", "yellow", "white",
#important directive
"!important",
#font rules
"font", "font-family", "font-style", "font-variant", "font-weight", "font-size",
#font values
"cursive", "fantasy", "monospace", "normal", "italic", "oblique", "small-caps",
"bold", "bolder", "lighter", "medium", "larger", "smaller",
"serif", "sans-serif",
#background rules
"background", "background-color", "background-image", "background-repeat", "background-attachment", "background-position",
#background values
"contained", "none", "top", "center", "bottom", "left", "right", "scroll", "fixed",
"repeat", "repeat-x", "repeat-y", "no-repeat",
#text rules
"word-spacing", "letter-spacing", "text-decoration", "vertical-align", "text-transform", "text-align", "text-indent", "text-transform", "text-shadow", "unicode-bidi", "line-height",
#text values
"normal", "none", "underline", "overline", "blink", "sub", "super", "middle", "top", "text-top", "text-bottom",
"capitalize", "uppercase", "lowercase", "none", "left", "right", "center", "justify",
"line-through",
#box rules
"margin", "margin-top", "margin-bottom", "margin-left", "margin-right",
"margin", "padding-top", "padding-bottom", "padding-left", "padding-right",
"border", "border-width", "border-style", "border-top", "border-top-width", "border-top-style", "border-bottom", "border-bottom-width", "border-bottom-style", "border-left", "border-left-width", "border-left-style", "border-right", "border-right-width", "border-right-style", "border-color",
#box values
"width", "height", "float", "clear",
"auto", "thin", "medium", "thick", "left", "right", "none", "both",
"none", "dotted", "dashed", "solid", "double", "groove", "ridge", "inset", "outset",
#display rules
"display", "white-space", 
"min-width", "max-width", "min-height", "max-height",
"outline-color", "outline-style", "outline-width",
#display values
"run-in", "inline-block", "list-item", "block", "inline", "none", "normal", "pre", "nowrap", "table-cell", "table-row", "table-row-group", "table-header-group", "inline-table", "table-column", "table-column-group", "table-cell", "table-caption"
#list rules
"list-style", "list-style-type", "list-style-image", "list-style-position",
#list values
"disc", "circle", "square", "decimal", "decimal-leading-zero", "none",
"lower-roman", "upper-roman", "lower-alpha", "upper-alpha", "lower-latin", "upper-latin",
#table rules
"border-collapse", "caption-side",
#table-values
"empty-cells", "table-layout",
#misc values/rules
"counter-increment", "counter-reset",
"marker-offset", "z-index",
"cursor", "direction", "marks", "quotes",
"clip", "content", "orphans", "overflow", "visibility",
#aural rules
"pitch", "range", "pitch-during", "cue-after", "pause-after", "cue-before", "pause-before", "speak-header", "speak-numeral", "speak-punctuation", "speed-rate", "play-during", "voice-family",
#aural values
"stress", "azimuth", "elevation", "pitch", "richness", "volume",
"page-break", "page-after", "page-inside"]
#@nonl
#@-node:ekr.20040401103539:css keywords
#@+node:ekr.20031218072017.374:elisp keywords
# EKR: needs more work.
elisp_keywords = [
    # Maybe...
    "error","princ",
    # More typical of other lisps...
    "apply","eval",
    "t","nil",
    "and","or","not",
    "cons","car","cdr",
    "cond",
    "defconst","defun","defvar",
    "eq","ne","equal","gt","ge","lt","le",
    "if",
    "let",
    "mapcar",
    "prog","progn",
    "set","setq",
    "type-of",
    "unless",
    "when","while"]
#@nonl
#@-node:ekr.20031218072017.374:elisp keywords
#@+node:ekr.20031218072017.375:html keywords
# No longer used by syntax colorer.
html_keywords = []

if 0: # Not used at present.
    unused_keywords = [
        # html constructs.
        "a","body","cf",
        "h1","h2","h3","h4","h5","h6",
        "head","html","hr",
        "i","img","li","lu","meta",
        "p","title","ul",
        # Common tags
        "caption","col","colgroup",
        "table","tbody","td","tfoot","th","thead","tr",
        "script","style"]

    html_specials = [ "<%","%>" ]
#@nonl
#@-node:ekr.20031218072017.375:html keywords
#@+node:ekr.20031218072017.376:java keywords
java_keywords = [
    "abstract","boolean","break","byte","byvalue",
    "case","cast","catch","char","class","const","continue",
    "default","do","double","else","extends",
    "false","final","finally","float","for","future",
    "generic","goto","if","implements","import","inner",
    "instanceof","int","interface","long","native",
    "new","null","operator","outer",
    "package","private","protected","public","rest","return",
    "short","static","super","switch","synchronized",
    "this","throw","transient","true","try",
    "var","void","volatile","while"]
#@nonl
#@-node:ekr.20031218072017.376:java keywords
#@+node:ekr.20031218072017.377:latex keywords
#If you see two idenitical words, with minor capitalization differences
#DO NOT ASSUME that they are the same word. For example \vert produces
#a single vertical line and \Vert produces a double vertical line
#Marcus A. Martin.

latex_special_keyword_characters = "@(){}%"

latex_keywords = [
    #special keyworlds
    "\\%", # 11/9/03
    "\\@", "\\(", "\\)", "\\{", "\\}",
    #A
    "\\acute", "\\addcontentsline", "\\addtocontents", "\\addtocounter", "\\address",
    "\\addtolength", "\\addvspace", "\\AE", "\\ae", "\\aleph", "\\alph", "\\angle",
    "\\appendix", 
    "\\approx",	"\\arabic", "\\arccos", "\\arcsin", "\\arctan", "\\ast", "\\author",
    #B
    "\\b", "\\backmatter", "\\backslash", "\\bar", "\\baselineskip", "\\baselinestretch",
    "\\begin", "\\beta", "\\bezier", "\\bf", "\\bfseries", "\\bibitem", "\\bigcap", 
    "\\bigcup", "\\bigodot", "\\bigoplus", "\\bigotimes", "\\bigskip", "\\biguplus", 
    "\\bigvee", "\\bigwedge",	"\\bmod", "\\boldmath", "\\Box", "\\breve", "\\bullet",
    #C
    "\\c", "\\cal", "\\caption", "\\cdot", "\\cdots", "\\centering", "\\chapter", 
    "\\check", "\\chi", "\\circ", "\\circle", "\\cite", "\\cleardoublepage", "\\clearpage", 
    "\\cline",	"\\closing", "\\clubsuit", "\\coprod", "\\copywright", "\\cos", "\\cosh", 
    "\\cot", "\\coth",	"csc",
    #D
    "\\d", "\\dag", "\\dashbox", "\\date", "\\ddag", "\\ddot", "\\ddots", "\\decl", 
    "\\deg", "\\Delta", 
    "\\delta", "\\depthits", "\\det", 
    "\\DH", "\\dh", "\\Diamond", "\\diamondsuit", "\\dim", "\\div", "\\DJ", "\\dj", 
    "\\documentclass", "\\documentstyle", 
    "\\dot", "\\dotfil", "\\downarrow",
    #E
    "\\ell", "\\em", "\\emph", "\\end", "\\enlargethispage", "\\ensuremath", 
    "\\enumi", "\\enuii", "\\enumiii", "\\enuiv", "\\epsilon", "\\equation", "\\equiv",	
    "\\eta", "\\example", "\\exists", "\\exp",
    #F
    "\\fbox", "\\figure", "\\flat", "\\flushbottom", "\\fnsymbol", "\\footnote", 
    "\\footnotemark", "\\fotenotesize", 
    "\\footnotetext", "\\forall", "\\frac", "\\frame", "\\framebox", "\\frenchspacing", 
    "\\frontmatter",
    #G
    "\\Gamma", "\\gamma", "\\gcd", "\\geq", "\\gg", "\\grave", "\\guillemotleft", 
    "\\guillemotright",	"\\guilsinglleft", "\\guilsinglright",
    #H
    "\\H", "\\hat", "\\hbar", "\\heartsuit", "\\heightits", "\\hfill", "\\hline", "\\hom",
    "\\hrulefill",	"\\hspace", "\\huge",	"\\Huge",	"\\hyphenation"
    #I
    "\\Im", "\\imath", "\\include", "includeonly", "indent", "\\index", "\\inf", "\\infty", 
    "\\input", "\\int", "\\iota",	"\\it", "\\item", "\\itshape",
    #J
    "\\jmath", "\\Join",
    #K
    "\\k", "\\kappa", "\\ker", "\\kill",
    #L
    "\\label", "\\Lambda", "\\lambda", "\\langle", "\\large", "\\Large", "\\LARGE", 
    "\\LaTeX", "\\LaTeXe", 
    "\\ldots", "\\leadsto", "\\left", "\\Leftarrow", "\\leftarrow", "\\lefteqn", "\\leq",
    "\\lg", "\\lhd", "\\lim", "\\liminf", "\\limsup", "\\line", 	"\\linebreak", 
    "\\linethickness", "\\linewidth",	"\\listfiles",
    "\\ll", "\\ln", "\\location", "\\log", "\\Longleftarrow", "\\longleftarrow", 
    "\\Longrightarrow",	"longrightarrow",
    #M
    "\\mainmatter", "\\makebox", "\\makeglossary", "\\makeindex","\\maketitle", "\\markboth", "\\markright",
    "\\mathbf", "\\mathcal", "\\mathit", "\\mathnormal", "\\mathop",
    "\\mathrm", "\\mathsf", "\\mathtt", "\\max", "\\mbox", "\\mdseries", "\\medskip",
    "\\mho", "\\min", "\\mp", "\\mpfootnote", "\\mu", "\\multicolumn", "\\multiput",
    #N
    "\\nabla", "\\natural", "\\nearrow", "\\neq", "\\newcommand", "\\newcounter", 
    "\\newenvironment", "\\newfont",
    "\\newlength",	"\\newline", "\\newpage", "\\newsavebox", "\\newtheorem", "\\NG", "\\ng",
    "\\nocite", "\\noindent", "\\nolinbreak", "\\nopagebreak", "\\normalsize",
    "\\not", "\\nu", "nwarrow",
    #O
    "\\Omega", "\\omega", "\\onecolumn", "\\oint", "\\opening", "\\oval", 
    "\\overbrace", "\\overline",
    #P
    "\\P", "\\page", "\\pagebreak", "\\pagenumbering", "\\pageref", "\\pagestyle", 
    "\\par", "\\parbox",	"\\paragraph", "\\parindent", "\\parskip", "\\part", 
    "\\partial", "\\per", "\\Phi", 	"\\phi",	"\\Pi", "\\pi", "\\pm", 
    "\\pmod", "\\pounds", "\\prime", "\\printindex", "\\prod", "\\propto", "\\protext", 
    "\\providecomamnd", "\\Psi",	"\\psi", "\\put",
    #Q
    "\\qbezier", "\\quoteblbase", "\\quotesinglbase",
    #R
    "\\r", "\\raggedbottom", "\\raggedleft", "\\raggedright", "\\raisebox", "\\rangle", 
    "\\Re", "\\ref", 	"\\renewcommand", "\\renewenvironment", "\\rhd", "\\rho", "\\right", 
    "\\Rightarrow",	"\\rightarrow", "\\rm", "\\rmfamily",
    "\\Roman", "\\roman", "\\rule", 
    #S
    "\\s", "\\samepage", "\\savebox", "\\sbox", "\\sc", "\\scriptsize", "\\scshape", 
    "\\searrow",	"\\sec", "\\section",
    "\\setcounter", "\\setlength", "\\settowidth", "\\settodepth", "\\settoheight", 
    "\\settowidth", "\\sf", "\\sffamily", "\\sharp", "\\shortstack", "\\Sigma", "\\sigma", 
    "\\signature", "\\sim", "\\simeq", "\\sin", "\\sinh", "\\sl", "\\SLiTeX",
    "\\slshape", "\\small", "\\smallskip", "\\spadesuit", "\\sqrt", "\\sqsubset",	
    "\\sqsupset", "\\SS",
    "\\stackrel", "\\star", "\\subsection", "\\subset", 
    "\\subsubsection", "\\sum", "\\sup", "\\supressfloats", "\\surd", "\\swarrow",
    #T
    "\\t", "\\table", "\\tableofcontents", "\\tabularnewline", "\\tan", "\\tanh", 
    "\\tau", "\\telephone",	"\\TeX", "\\textbf",
    "\\textbullet", "\\textcircled", "\\textcompworkmark",	"\\textemdash", 
    "\\textendash", "\\textexclamdown", "\\textheight", "\\textquestiondown", 
    "\\textquoteblleft", "\\textquoteblright", "\\textquoteleft",
    "\\textperiod", "\\textquotebl", "\\textquoteright", "\\textmd", "\\textit", "\\textrm", 
    "\\textsc", "\\textsl", "\\textsf", "\\textsuperscript", "\\texttt", "\\textup",
    "\\textvisiblespace", "\\textwidth", "\\TH", "\\th", "\\thanks", "\\thebibligraphy",
    "\\Theta", "theta", 
    "\\tilde", "\\thinlines", 
    "\\thispagestyle", "\\times", "\\tiny", "\\title",	"\\today", "\\totalheightits", 
    "\\triangle", "\\tt", 
    "\\ttfamily", "\\twocoloumn", "\\typeout", "\\typein",
    #U
    "\\u", "\\underbrace", "\\underline", "\\unitlength", "\\unlhd", "\\unrhd", "\\Uparrow",
    "\\uparrow",	"\\updownarrow", "\\upshape", "\\Upsilon", "\\upsilon", "\\usebox",	
    "\\usecounter", "\\usepackage", 
    #V
    "\\v", "\\value", "\\varepsilon", "\\varphi", "\\varpi", "\\varrho", "\\varsigma", 
    "\\vartheta", "\\vdots", "\\vec", "\\vector", "\\verb", "\\Vert", "\\vert", 	"\\vfill",
    "\\vline", "\\vphantom", "\\vspace",
    #W
    "\\widehat", "\\widetilde", "\\widthits", "\\wp",
    #X
    "\\Xi", "\\xi",
    #Z
    "\\zeta" ]
#@nonl
#@-node:ekr.20031218072017.377:latex keywords
#@+node:ekr.20031218072017.378:pascal keywords
pascal_keywords = [
    "and","array","as","begin",
    "case","const","class","constructor","cdecl"
    "div","do","downto","destructor","dispid","dynamic",
    "else","end","except","external",
    "false","file","for","forward","function","finally",
    "goto","if","in","is","label","library",
    "mod","message","nil","not","nodefault""of","or","on",
    "procedure","program","packed","pascal",
    "private","protected","public","published",
    "record","repeat","raise","read","register",
    "set","string","shl","shr","stdcall",
    "then","to","true","type","try","until","unit","uses",
    "var","virtual","while","with","xor"
    # object pascal
    "asm","absolute","abstract","assembler","at","automated",
    "finalization",
    "implementation","inherited","initialization","inline","interface",
    "object","override","resident","resourcestring",
    "threadvar",
    # limited contexts
    "exports","property","default","write","stored","index","name" ]
#@nonl
#@-node:ekr.20031218072017.378:pascal keywords
#@+node:ekr.20031218072017.379:perl keywords
perl_keywords = [
    "continue","do","else","elsif","format","for","format","for","foreach",
    "if","local","package","sub","tr","unless","until","while","y",
    # Comparison operators
    "cmp","eq","ge","gt","le","lt","ne",
    # Matching ooperators
    "m","s",
    # Unary functions
    "alarm","caller","chdir","cos","chroot","exit","eval","exp",
    "getpgrp","getprotobyname","gethostbyname","getnetbyname","gmtime",
    "hex","int","length","localtime","log","ord","oct",
    "require","reset","rand","rmdir","readlink",
    "scalar","sin","sleep","sqrt","srand","umask",
    # Transfer ops
    "next","last","redo","go","dump",
    # File operations...
    "select","open",
    # FL ops
    "binmode","close","closedir","eof",
    "fileno","getc","getpeername","getsockname","lstat",
    "readdir","rewinddir","stat","tell","telldir","write",
    # FL2 ops
    "bind","connect","flock","listen","opendir",
    "seekdir","shutdown","truncate",
    # FL32 ops
    "accept","pipe",
    # FL3 ops
    "fcntl","getsockopt","ioctl","read",
    "seek","send","sysread","syswrite",
    # FL4 & FL5 ops
    "recv","setsocket","socket","socketpair",
    # Array operations
    "pop","shift","split","delete",
    # FLIST ops
    "sprintf","grep","join","pack",
    # LVAL ops
    "chop","defined","study","undef",
    # f0 ops
    "endhostent","endnetent","endservent","endprotoent",
    "endpwent","endgrent","fork",
    "getgrent","gethostent","getlogin","getnetent","getppid",
    "getprotoent","getpwent","getservent",
    "setgrent","setpwent","time","times","wait","wantarray",
    # f1 ops
    "getgrgid","getgrnam","getprotobynumber","getpwnam","getpwuid",
    "sethostent","setnetent","setprotoent","setservent",
    # f2 ops
    "atan2","crypt",
    "gethostbyaddr","getnetbyaddr","getpriority","getservbyname","getservbyport",
    "index","link","mkdir","msgget","rename",
    "semop","setpgrp","symlink","unpack","waitpid",
    # f2 or 3 ops
    "index","rindex","substr",
    # f3 ops
    "msgctl","msgsnd","semget","setpriority","shmctl","shmget","vec",
    # f4 & f5 ops
    "semctl","shmread","shmwrite","msgrcv",
    # Assoc ops
    "dbmclose","each","keys","values",
    # List ops
    "chmod","chown","die","exec","kill",
    "print","printf","return","reverse",
    "sort","system","syscall","unlink","utime","warn"]
#@nonl
#@-node:ekr.20031218072017.379:perl keywords
#@+node:ekr.20031218072017.380:php keywords
php_keywords = [ # 08-SEP-2002 DTHEIN
    "__CLASS__", "__FILE__", "__FUNCTION__", "__LINE__",
    "and", "as", "break",
    "case", "cfunction", "class", "const", "continue",
    "declare", "default", "do",
    "else", "elseif", "enddeclare", "endfor", "endforeach",
    "endif", "endswitch",  "endwhile", "eval", "extends",
    "for", "foreach", "function", "global", "if",
    "new", "old_function", "or", "static", "switch",
    "use", "var", "while", "xor" ]
    
# The following are supposed to be followed by ()
php_paren_keywords = [
    "array", "die", "echo", "empty", "exit",
    "include", "include_once", "isset", "list",
    "print", "require", "require_once", "return",
    "unset" ]
    
# The following are handled by special case code:
# "<?php", "?>"
#@-node:ekr.20031218072017.380:php keywords
#@+node:ekr.20031218072017.381:python keywords
python_keywords = [
    "and",       "del",       "for",       "is",        "raise",    
    "assert",    "elif",      "from",      "lambda",    "return",   
    "break",     "else",      "global",    "not",       "try",      
    "class",     "except",    "if",        "or",        "yield",   
    "continue",  "exec",      "import",    "pass",      "while",
    "def",       "finally",   "in",        "print"]
#@nonl
#@-node:ekr.20031218072017.381:python keywords
#@+node:ekr.20040331145826:rapidq keywords
rapidq_keywords = [
# Syntax file for RapidQ
"$APPTYPE","$DEFINE","$ELSE","$ENDIF","$ESCAPECHARS","$IFDEF","$IFNDEF",
"$INCLUDE","$MACRO","$OPTIMIZE","$OPTION","$RESOURCE","$TYPECHECK","$UNDEF",
"ABS","ACOS","ALIAS","AND","AS","ASC","ASIN","ATAN","ATN","BIN$","BIND","BYTE",
"CALL","CALLBACK","CALLFUNC","CASE","CEIL","CHDIR","CHDRIVE","CHR$","CINT",
"CLNG","CLS","CODEPTR","COMMAND$","COMMANDCOUNT","CONSOLE","CONST","CONSTRUCTOR",
"CONVBASE$","COS","CREATE","CSRLIN","CURDIR$","DATA","DATE$","DEC","DECLARE",
"DEFBYTE","DEFDBL","DEFDWORD","DEFINT","DEFLNG","DEFSHORT","DEFSNG","DEFSTR",
"DEFWORD","DELETE$","DIM","DIR$","DIREXISTS","DO","DOEVENTS","DOUBLE","DWORD",
"ELSE","ELSEIF","END","ENVIRON","ENVIRON$","EVENT","EXIT","EXP","EXTENDS",
"EXTRACTRESOURCE","FIELD$","FILEEXISTS","FIX","FLOOR","FOR","FORMAT$","FRAC",
"FUNCTION","FUNCTIONI","GET$","GOSUB","GOTO","HEX$","IF","INC","INITARRAY",
"INKEY$","INP","INPUT","INPUT$","INPUTHANDLE","INSERT$","INSTR","INT","INTEGER",
"INV","IS","ISCONSOLE","KILL","KILLMESSAGE","LBOUND","LCASE$","LEFT$","LEN",
"LFLUSH","LIB","LIBRARYINST","LOCATE","LOG","LONG","LOOP","LPRINT","LTRIM$",
"MEMCMP","MESSAGEBOX","MESSAGEDLG","MID$","MKDIR","MOD","MOUSEX","MOUSEY",
"NEXT","NOT","OFF","ON","OR","OUT","OUTPUTHANDLE","PARAMSTR$","PARAMSTRCOUNT",
"PARAMVAL","PARAMVALCOUNT","PCOPY","PEEK","PLAYWAV","POKE","POS","POSTMESSAGE",
"PRINT","PROPERTY","QUICKSORT","RANDOMIZE","REDIM","RENAME","REPLACE$",
"REPLACESUBSTR$","RESOURCE","RESOURCECOUNT","RESTORE","RESULT","RETURN",
"REVERSE$","RGB","RIGHT$","RINSTR","RMDIR","RND","ROUND","RTRIM$","RUN",
"SCREEN","SELECT","SENDER","SENDMESSAGE","SETCONSOLETITLE","SGN","SHELL",
"SHL","SHORT","SHOWMESSAGE","SHR","SIN","SINGLE","SIZEOF","SLEEP","SOUND",
"SPACE$","SQR","STACK","STATIC","STEP","STR$","STRF$","STRING","STRING$",
"SUB","SUBI","SWAP","TALLY","TAN","THEN","TIME$","TIMER","TO","TYPE","UBOUND",
"UCASE$","UNLOADLIBRARY","UNTIL","VAL","VARIANT","VARPTR","VARPTR$","VARTYPE",
"WEND","WHILE","WITH","WORD","XOR"]
#@nonl
#@-node:ekr.20040331145826:rapidq keywords
#@+node:ekr.20031218072017.382:rebol keywords
rebol_keywords = [
#Jason 2003-07-03 
#based on UltraEdit syntax highlighting
"about", "abs", "absolute", "add", "alert", "alias", "all", "alter", "and", "and~", "any", "append", "arccosine", "arcsine", "arctangent", "array", "ask", "at",  
"back", "bind", "boot-prefs", "break", "browse", "build-port", "build-tag",  
"call", "caret-to-offset", "catch", "center-face", "change", "change-dir", "charset", "checksum", "choose", "clean-path", "clear", "clear-fields", "close", "comment", "complement", "compose", "compress", "confirm", "continue-post", "context", "copy", "cosine", "create-request", "crypt", "cvs-date", "cvs-version",  
"debase", "decode-cgi", "decode-url", "decompress", "deflag-face", "dehex", "delete", "demo", "desktop", "detab", "dh-compute-key", "dh-generate-key", "dh-make-key", "difference", "dirize", "disarm", "dispatch", "divide", "do", "do-boot", "do-events", "do-face", "do-face-alt", "does", "dsa-generate-key", "dsa-make-key", "dsa-make-signature", "dsa-verify-signature",  
"echo", "editor", "either", "else", "emailer", "enbase", "entab", "exclude", "exit", "exp", "extract", 
"fifth", "find", "find-key-face", "find-window", "flag-face", "first", "flash", "focus", "for", "forall", "foreach", "forever", "form", "forskip", "fourth", "free", "func", "function",  
"get", "get-modes", "get-net-info", "get-style",  
"halt", "has", "head", "help", "hide", "hide-popup",  
"if", "import-email", "in", "inform", "input", "insert", "insert-event-func", "intersect", 
"join", 
"last", "launch", "launch-thru", "layout", "license", "list-dir", "load", "load-image", "load-prefs", "load-thru", "log-10", "log-2", "log-e", "loop", "lowercase",  
"make", "make-dir", "make-face", "max", "maximum", "maximum-of", "min", "minimum", "minimum-of", "mold", "multiply",  
"negate", "net-error", "next", "not", "now",  
"offset-to-caret", "open", "open-events", "or", "or~", 
"parse", "parse-email-addrs", "parse-header", "parse-header-date", "parse-xml", "path-thru", "pick", "poke", "power", "prin", "print", "probe", "protect", "protect-system",  
"q", "query", "quit",  
"random", "read", "read-io", "read-net", "read-thru", "reboot", "recycle", "reduce", "reform", "rejoin", "remainder", "remold", "remove", "remove-event-func", "rename", "repeat", "repend", "replace", "request", "request-color", "request-date", "request-download", "request-file", "request-list", "request-pass", "request-text", "resend", "return", "reverse", "rsa-encrypt", "rsa-generate-key", "rsa-make-key", 
"save", "save-prefs", "save-user", "scroll-para", "second", "secure", "select", "send", "send-and-check", "set", "set-modes", "set-font", "set-net", "set-para", "set-style", "set-user", "set-user-name", "show", "show-popup", "sine", "size-text", "skip", "sort", "source", "split-path", "square-root", "stylize", "subtract", "switch",  
"tail", "tangent", "textinfo", "third", "throw", "throw-on-error", "to", "to-binary", "to-bitset", "to-block", "to-char", "to-date", "to-decimal", "to-email", "to-event", "to-file", "to-get-word", "to-hash", "to-hex", "to-idate", "to-image", "to-integer", "to-issue", "to-list", "to-lit-path", "to-lit-word", "to-local-file", "to-logic", "to-money", "to-none", "to-pair", "to-paren", "to-path", "to-rebol-file", "to-refinement", "to-set-path", "to-set-word", "to-string", "to-tag", "to-time", "to-tuple", "to-url", "to-word", "trace", "trim", "try",  
"unfocus", "union", "unique", "uninstall", "unprotect", "unset", "until", "unview", "update", "upgrade", "uppercase", "usage", "use",  
"vbug", "view", "view-install", "view-prefs",  
"wait", "what", "what-dir", "while", "write", "write-io",  
"xor", "xor~",  
"action!", "any-block!", "any-function!", "any-string!", "any-type!", "any-word!",  
"binary!", "bitset!", "block!",  
"char!",  
"datatype!", "date!", "decimal!", 
"email!", "error!", "event!",  
"file!", "function!",  
"get-word!",  
"hash!",  
"image!", "integer!", "issue!",  
"library!", "list!", "lit-path!", "lit-word!", "logic!",  
"money!",  
"native!", "none!", "number!",  
"object!", "op!",  
"pair!", "paren!", "path!", "port!",  
"refinement!", "routine!",  
"series!", "set-path!", "set-word!", "string!", "struct!", "symbol!",  
"tag!", "time!", "tuple!",  
"unset!", "url!",  
"word!",  
"any-block?", "any-function?", "any-string?", "any-type?", "any-word?",  
"binary?", "bitset?", "block?",  
"char?", "connected?", "crypt-strength?", 
"datatype?", "date?", "decimal?", "dir?",  
"email?", "empty?", "equal?", "error?", "even?", "event?", "exists?", "exists-key?",
"file?", "flag-face?", "found?", "function?",  
"get-word?", "greater-or-equal?", "greater?",  
"hash?", "head?",  
"image?", "in-window?", "index?", "info?", "input?", "inside?", "integer?", "issue?",  
"length?", "lesser-or-equal?", "lesser?", "library?", "link-app?", "link?", "list?", "lit-path?", "lit-word?", "logic?",  
"modified?", "money?",  
"native?", "negative?", "none?", "not-equal?", "number?",  
"object?", "odd?", "offset?", "op?", "outside?",  
"pair?", "paren?", "path?", "port?", "positive?",  
"refinement?", "routine?",  
"same?", "screen-offset?", "script?", "series?", "set-path?", "set-word?", "size?", "span?", "strict-equal?", "strict-not-equal?", "string?", "struct?",  
"tag?", "tail?", "time?", "tuple?", "type?",  
"unset?", "url?",  
"value?", "view?", 
"within?", "word?",  
"zero?"
]
#@nonl
#@-node:ekr.20031218072017.382:rebol keywords
#@+node:ekr.20040401111125:shell keywords
shell_keywords = [
    # reserved keywords
    "case","do","done","elif","else","esac","fi",
    "for","if","in","then",
    "until","while",
    "break","cd","chdir","continue","eval","exec",
    "exit","kill","newgrp","pwd","read","readonly",
    "return","shift","test","trap","ulimit",
    "umask","wait" ]
#@nonl
#@-node:ekr.20040401111125:shell keywords
#@+node:ekr.20031218072017.383:tcl/tk keywords
tcltk_keywords = [ # Only the tcl keywords are here.
    "after",     "append",    "array",
    "bgerror",   "binary",    "break",
    "catch",     "cd",        "clock",
    "close",     "concat",    "continue",
    "dde",
    "encoding",  "eof",       "eval",
    "exec",      "exit",      "expr",
    "fblocked",  "fconfigure","fcopy",     "file",      "fileevent",
    "filename",  "flush",     "for",       "foreach",   "format",
    "gets",      "glob",      "global",
    "history",
    "if",        "incr",      "info",      "interp",
    "join",
    "lappend",   "lindex",    "linsert",   "list",      "llength",
    "load",      "lrange",    "lreplace",  "lsearch",   "lsort",
    "memory",    "msgcat",
    "namespace",
    "open",
    "package",   "parray",    "pid",
    "proc",      "puts",      "pwd",
    "read",      "regexp",    "registry",   "regsub",
    "rename",    "resource",  "return",
    "scan",      "seek",      "set",        "socket",   "source",
    "split",     "string",    "subst",      "switch",
    "tell",      "time",      "trace",
    "unknown",   "unset",     "update",     "uplevel",   "upvar",
    "variable",  "vwait",
    "while" ]
#@nonl
#@-node:ekr.20031218072017.383:tcl/tk keywords
#@-node:ekr.20031218072017.371:<< define colorizer keywords >> colorizer
#@-node:ekr.20031218072017.367:How to add support for a new language
#@-node:ekr.20031218072017.365:How to...
#@+node:ekr.20040706072605:Ideas for later...
#@+node:EKR.20040512082621:HTML widgets
#@+node:EKR.20040512082621.1:htmllib.tcl
http://sourceforge.net/forum/message.php?msg_id=2565345
By: nobody

I just met a nice TCL-based html help viewer bundled with the evaluation version
of Fujitsu-Siemens OpenFT for Unix (see
fujitsu-siemens.com/products/software/openseas/openft.html)

It is based on a TCL library htmllib.tcl, written by Stephen Uhler in 1995 while
working in Sun's TCL group.Iit seemts that this lib is owned by Sun and i'm
not certain about license. It is freely downloadable, anyway.

The usage is really simple -- you have to create a text widget, a string variable
containing html text and a link callback, then feed all three to the library
routine. It should be not hard pythonize this process.

see http://www.usenix.org/publications/login/1999-8/features/tclsh.html,
ftp://ftp.scriptics.com/pub/tcl/misc/html_library-0.3.tar.gz
or just google for htmllib.tcl
#@-node:EKR.20040512082621.1:htmllib.tcl
#@-node:EKR.20040512082621:HTML widgets
#@+node:ekr.20040226085005:Java notes
@nocolor
http://sourceforge.net/forum/message.php?msg_id=2442609
By: nobody

>>Anyway, I can import java, javax, javax.swing. And I just created my first
JTree.

good man.  You will probably be subclassing JApplet.  You subclass a Java class
like this:

class EdwardsApplet(JApplet):
   pass

Id recommend getting the SDK javadoc on your PC or have a good link to the SDK
javadoc.  Read the JApplet doc in the Swing package.  The thing to keep in mind
is that you will be adding things to the JApplet's content pane, which will
be using a Layout Manager.  I believe the default for it is the BorderLayout.
This means after you get a reference to the ContentPane, you should be able
to add your components with:

cp = getContentPane()
cp.add( JTree() , BorderLayout.EAST )

Ill have to look at how Jython should package applets but you will be using,
I believe, a program called appletviewer that comes with the JDK to view your
applet.  Remember that Jython is a couple of versions behind CPython, so stick
to only features available in 2.1.  As is, you will be calling things like you
did in Python.  The Jython home page might have tips on building an applet.

What would be cool is if Leo could be totally packaged as a Jython applet, then
a demoer could test a pretty full fledged Leo throught there browser. :)

______________________________________________________________________
You are receiving this email because you elected to monitor this forum.
To stop monitoring this forum, login to SourceForge.net and visit: 
https://sourceforge.net/forum/unmonitor.php?forum_id=10226
#@-node:ekr.20040226085005:Java notes
#@+node:ekr.20040125121407:Leo & Emacs
@nocolor
#@nonl
#@+node:ekr.20040125121407.1:comment
https://sourceforge.net/forum/message.php?msg_id=2389876
By: randomandy

Is it only me who sees this as a question on how to reinvent the wheel? (or
in the case of emacs, how to reinvent the <i>everything</i>.)

Leo and Python both seem so well suited as wonderful hierarchal glue programs.
And both are so elegant in the way their simple functionality brings such power
and order to the cause. It just seems it would be a shame to take something
so novel and unique and try to turn it into <i>yet another</i> huge text editor.

I'm with <A HREF="http://sourceforge.net/forum/message.php?msg_id=2345873">Danny
</A> on this one. The ideal solution is to find the most elegant and seamless
way to splice one's own beloved text editor (or multipurpose editor/OS) in with
the Leo paradigm. Have Leo hand off the text duties to the editor, or have the
editor deliver heirarchy commands to Leo.

I'm also quite curious if this makes a good tie in with SciTE. SciTE produces
stunningly readible language highlighting/formatting. Could it be employed for
basic cell text display, and then for heavier editing, a keystroke or button
could open the cell text in one's preferred weapons grade text editor?

Scintilla also has a similarly beautiful code-to-html and code-to-pdf capability
that seems very suited to the literary part of the Leo paradigm: publication.
It would be nice if that code could be exploited as well.

This Leo is really a marvelous work. It's transforming the way I think (i.e.
making it possible again). Nice work, Edward.
#@-node:ekr.20040125121407.1:comment
#@+node:ekr.20040125121407.2:comment
By: dannyobrien ( danny o'brien ) 
 RE: What would it take to turn Leo into Emacs   
2003-12-23 09:18  

 I agree with the embedding; I've used the vim plugin and it works well, but actually embedding the editor directly into the text field of leo (and allowing a range of keyboard shortcuts for eg headline editing) would be perfect.

There is some support for this in gvim, the GUI version of vim that comes as standard. This can be run so as its GUI is "embedded" in another GTK widget, using that library's GtkSocket/GtkPlug system. A quick demo of that (and how to do it in python) is here:

http://www.daa.com.au/pipermail/pygtk/2003-October/006185.html

To see this working with gvim, run the second (socket.py) program on that page then type

gvim --socketid <number generated by socket.py>

I'm not sure how you could do this in other widget libraries - I don't know much about X Windows, but I suppose it would need support in vim as well as the widget set.
 
#@-node:ekr.20040125121407.2:comment
#@+node:ekr.20040125121407.3:comment
https://sourceforge.net/forum/message.php?msg_id=2388448
By: mdawson

I use XEmacs as my text editor.  The first thing I did when
evaluating Leo was to set up "open with" to use XEmacs for editing
Leo body text.

My progress so far:

- my Open_With Plugin opens a Leo node as a foreground buffer in
XEmacs, or a background (invisible) buffer in XEmacs.

- my Open_Tree Plugin opens a sub-tree of Leo nodes as background
buffers in XEmacs.

- my filename modification plugin changes the temporary file names
used by Leo so that they can be spotted more easily in an XEmacs
buffer listing (e.g. ibuffer).

- an elisp function to kill all XEmacs Leo buffers at once.

- another elisp function to indent and unindent the Leo comments in
derived Python source, which improves the readability of code.

- my setup of the elisp Multiple-Major-Modes XEmacs package, so that
XEmacs is in text-mode in Leo @doc sections, and the correct
language mode in @code sections.

Any of these might be able to be adapted for your own use. They
should all work with Emacs as well as XEmacs, but I've not tested
that.

These are all outlined in Appendix "C. XEmacs Text Editor" of the
document at:
    http://devguide.leo.marshallresearch.ca

and the Leo outline that contains them is available
at:
    http://leo.marshallresearch.ca


    ----------------------------------------
    Michael Dawson

 
#@-node:ekr.20040125121407.3:comment
#@-node:ekr.20040125121407:Leo & Emacs
#@+node:ekr.20040107064101.5:Zope notes
#@+node:ekr.20040107065006:posting
@nocolor

Yes he's absolutely right -- focus on the ZODB.

..stay alway from ZTP. ZPT, TPZ, CMF, Plone and all that other stuff for now.

I jsut came accross a handy slide show overview from last spring:
http://jace.seacrow.com/tech/zope/blug-zodb

BerkeyDB Storage is cool too and fits Leo well I think. plays nicely wiht ZODB
standalnioe and in Zope.
#@-node:ekr.20040107065006:posting
#@+node:ekr.20040107064854:example Code
from ZODG import FileStorage,DB
from Persistence import Persistent

# Connect to db.
# FileStorage is standard: entire db is stored in a single file.
storage = FileStorage.FileStorage("/tmp/test-filestorage.fs")
db = DB.(storage)
conn = db.open()

# Get the root of the db.
root = conn.root()

# Defining user classes.
class leoData(Persistent):
	pass
	
# Commit or revert.
get_transaction().commit()
get_transaction().abort()
#@nonl
#@-node:ekr.20040107064854:example Code
#@+node:ekr.20040107080609.1:Zshell
@nocolor

By: jasonic ( Jason Cunliffe )
ZShell  
2003-12-31 22:25

Hi, Just another friendly reminder to check out Jerome Alet's ZShell, one of Zope's best kept secrets:

http://www.librelogiciel.com/software/

ZShell : Manipulate the Zope Object DataBase with Unix shell like commands

and also

ZShellScripts : Unifies the Zope notion of Scripts and provides several Script interpreters : Python, Unix shell , Lisp, Perl, PHP, Ruby, and Zope ZShell

Not only for obvious usefullness, but also as a valuable study of Python access to the ZODB.

JAXML is cool too..
http://www.librelogiciel.com/software/jaxml/action_Presentation

- Jason
#@nonl
#@-node:ekr.20040107080609.1:Zshell
#@+node:ekr.20040107064854.1:@url http://zope.org/Products/StandaloneZODB
#@-node:ekr.20040107064854.1:@url http://zope.org/Products/StandaloneZODB
#@+node:ekr.20040107064854.2:@url http://jace.seacrow.com/tech/zope/blug-zodb
#@-node:ekr.20040107064854.2:@url http://jace.seacrow.com/tech/zope/blug-zodb
#@-node:ekr.20040107064101.5:Zope notes
#@+node:ekr.20031218072017.404:LeoN, Zope & collaboration info
@nocolor
#@nonl
#@+node:ekr.20031218072017.405:Kent Tenny Notes
@nocolor

Outlook: server for email, addresses & calendar.  Groupware.  Chandler similar.

Zope: back end is ZODB.  Zope like an OS: run Python code on Zope.

Zope: another way to access Leo files.  Maybe twisted is better?

Wiki anology: edit Leo files with browser.  Write through the web.

longrun.org

Wiki principles: 
	- Sharing is 90% of collaboration.
	- Zope: Subscribe to a wiki: email when page changes.
	- RSS: xml that defines piece of info(tile,url,abstract)
		- Client has a list of rss feeds: an xml file.
		- List of intesting people: notified when they say something.

Two goals:
	- publish Leo files
	- edit Leo files

Brother needs cvs.
Kent not so worried about cvs.
	-Leo file is a web site!
	- Helper layer between user and OS.
		- Look at aap project.  Author of vim. a-p.org
			- Replacement for make in Python.  Automating tool.
		- Expert prepares Leo file.  User uses it.
#@nonl
#@-node:ekr.20031218072017.405:Kent Tenny Notes
#@+node:ekr.20031218072017.406:url's
#@+node:ekr.20031218072017.407:@url http://24.243.129.68:8080/members/sandbox
#@-node:ekr.20031218072017.407:@url http://24.243.129.68:8080/members/sandbox
#@+node:ekr.20031218072017.408:@url http://www.zopelabs.com/cookbook
#@-node:ekr.20031218072017.408:@url http://www.zopelabs.com/cookbook
#@+node:ekr.20031218072017.409:@url http://zwiki.org/FrontPage  Zope implementation of wiki
#@-node:ekr.20031218072017.409:@url http://zwiki.org/FrontPage  Zope implementation of wiki
#@-node:ekr.20031218072017.406:url's
#@+node:ekr.20031218072017.410:Collaboration & Sharing
#@+node:ekr.20031218072017.411:From Rodrigo
Developers Forum
By: rodrigo_b ( Rodrigo Benenson ) 
 RE: Leo over the network   
2003-05-10 00:06  
So this is my first proposal: 

Requirements 
-------------------- 

* Read remote outlines. 
** With Leo clients. 
** Over the web. 

* Edit remote outlines. 

* Import remote outlines (retrieve outlines from the web). 

* Synchronize local outlines with remote ones (web to local and local to web). 

* Publish outlines (send outlines to the web). 

* The Leo client have to be keept lighweigth. 

* The Leo remote outline access server should be a lighweigth daemon. 

* This daemon should automagically render HTML from the outlines. 

* The outlines should be editable from the web and via Leo client. 

* Concurency management is must. 

* The remote servers should be included in the leo client as leo nodes (just like leo files, but remotes). 
"@leo-outline leo.server.org:854" 

* By this way I could have access to local server nodes. 
"@leo-outline localhost:854" 

* The remote server should offer one and only one big outline with sub nodes, and so on, and so on... 

* At least the concurency should be managed as "when someone write, all the other ones only can read" 

* It is better if Leo devellop simultaneaously some hypertext/wiki extensions. 

---------------------------- 
End of requeriments 

This requeriments requires a client-server architecture, with basic commands as: 
- Update node 
- Lock/release node 
- Edit outline 
- Download outline 
- Upload outline 

well that is by the moment, I hope that we will be able to create a Finite, clear, requeriments list for this branch of Leo. 

RodrigoB.  

#@-node:ekr.20031218072017.411:From Rodrigo
#@-node:ekr.20031218072017.410:Collaboration & Sharing
#@+node:ekr.20031218072017.412:Zope
#@+node:ekr.20031218072017.413:From Rodrigo re: Zope.
Open Discussion
https://sourceforge.net/forum/message.php?msg_id=2007586
By: rodrigo_b

z2.py,
>Supposing that that I did find this file, what would I be looking for? 

This is the Main script, the principal program, the code that startup all the
servers, the only python program that make run Zope, it the code called by start.py,
and it is the one to which you pass the command lines.

With the command line you can indicate which services to start up at which ports.
This is IMPORTANT. Also you can enable/disable the Debug mode.

python z2.py --help will give you some infos about what I'm talking about.

In linux the debug or not debug mode, enable the console or daemon mode (that
means 'background task mode').

In windows, I'm not sure that disabling the debug mode will be enough.
I know that at the install time you can setup Zope as a Windows Service, so
it will start automatically every time Windows Startup, and it will not open
a console window.

But first look at the debug mode.

Start.bat give some defaults command lines to z2.py

Webdav,
>What issues are involved in this choice, and why should I care today? 

from www.webdav.org

What is WebDAV? 
Briefly: WebDAV stands for "Web-based Distributed Authoring and Versioning".
It is a set of extensions to the HTTP protocol which allows users to collaboratively
edit and manage files on remote web servers.

For example that means that you can open you Windows Explorer (from your mail
I understand that you work on an MsWindows OS),
tip the url "localhost:%i"%(your webdav port) and you will be able to navigate,
view and edit the Zope Objects just as a normal file system (well, almost).

WebDav is a standard and there are Python implementations. WebDav is support
by  Oscom.

WebDav is cool.
WebDav is the 'highest level tool'.

ZODB,

>Does that mean that gnx's aren't needed with Zope? Could Leo nodes live in
the ZODB?

You have to thinks to ZODB just as what it is: a Persistent Object Database.
Most objects in Zope are Persistents, that mean that their instances do not
die when you shutdown the server.

The ZODB store his data in it own format.
I think that GNX should be keeped.
You have to basic ways to put nodes into Zope.

First: the hard way: create a new Product (Products are something like Zope
plugins) that is based on the Leo code, but were there is no node storage, instead
the node should be Persistents. Then add rendering code to this objects.

Leo node object + Persistence + ZClass + Rendering Code -> Leo Zope node.

Additionaly you should create an Folder like object that should be an 'Leo Outline
Zope Object',  actuating as an Leo nodes container.

This shema is similar to the Zwiki way, with a Zwiki Web and the Zwiki Pages.

Second: Use A zope folder just as Leo manage the @file nodes. Let have simple
DTMLDocuments, edited via WebDav, with <dtml-comments> , and stuff like that.
The Leo import/export that nodes.

RodrigoB.

#@-node:ekr.20031218072017.413:From Rodrigo re: Zope.
#@+node:ekr.20031218072017.414:Clarification from Kent Tenny
Open Discussion
https://sourceforge.net/forum/message.php?msg_id=2009081
By: ktenney

Edward,

I don't see ZLeo replacing Leo, rather a method of accessing
Leo files.

When I write, I almost always want it to be web accessable,
so that I can access it from any browser, and so that I can
share it easily. I would like myfile.leo to live
at http://longrun.org/leo/myfile.leo. It can be read and
written to from any browser (according to how permissions are
configured) The page describing how to configure Apache would
be found at http://longrun.org/leo/myfile.leo/Apache/configure
The only requirement to work with Leo files is a browser.

I wouldn't want to lose the capability to edit outside
the browser, using a standalone version of Leo or Zope's
ExternalEditor product. ExternalEditor allows me to click
an icon to open the page I'm viewing in any editor. I could
open it in Leo as a Leo file, or open just the page in
Vim (http://vim.sourceforge.net/index.php)

Zope is ponderous, I think of it as more of a platform
than an application. My understanding of how Zope works
grows slowly, in the mean time my focus is on _products_.
Installing a product in Zope is like installing an application
in Windows or Linux.

One of the most evolved products is Plone/CMF http://plone.org
which is basically a turnkey web site.

twisted http://twistedmatrix.com is a brilliant set of network
programming tools. That's all I know about it.

I'm not sure about Chandler (http://www.osafoundation.org/) 
(they did choose Python and ZODB http://www.osafoundation.org/technology.htm)

You might try subscribing to a Zope mailing list or two
http://www.zope.org/Resources/MailingLists
The community of users and developers is very important to Zope.

Thanks,
Kent
#@-node:ekr.20031218072017.414:Clarification from Kent Tenny
#@+node:ekr.20031218072017.415:From Rodrigo re: ip
Open Discussion
https://sourceforge.net/forum/message.php?msg_id=2007817
By: rodrigo_b

If zope is running some server then this server will be accesible from your
network if and only if there is no firewall in the way.

The people can access to your services using (normally on internet you do not
have a domain name)

your_ip:the_service_port

Example:
zope http service on port 8080 on your machine.
When  you connect to internet your machine got an extra IP.
Then simple put on the web browser

http://your_conexion_ip:8080

and Tada you will see the root_zope/index_html object rendered intro HTML.

Most of the ISP give you a dinamic IP.
Some companies provides you dinamic IP Domain Name services, allowing to attach
a domain name to your machine dinamically (each time you reconect).

then you can have:

http://leo.edward.com:8080/

The 8080 stuff can be avoied if you setup zope to use the standard port 80 for
HTTP service.

With this in mind you can access ftp

ftp://your_ip_or_domain_name:8021

or webdav, or anything else.
#@-node:ekr.20031218072017.415:From Rodrigo re: ip
#@+node:ekr.20031218072017.416:Other servers
Open Discussion
https://sourceforge.net/forum/message.php?msg_id=2007832
By: rodrigo_b

I would made a warning.

Zope IT IS NOT the only way to obtain an local HTTP server, pythonic and
flexible.

There is a lot of other way.

Also Zope IT IS NOT THE BEST pythonic http/ftp/webdav or anything server
aviable.

I think that we should define better 

What we want to do?

before choosing the tool.

As I said, I had already used Zope, I choosed it because of very specific features,
but nothing indicate that Zope is the best way to get Leo to the colaborative
network universe.

I think that we should at least consider:
- SimpleHTTPServer
- To take of the Medusa Server from Zope (that is use Zope code in the standard
Leo distribution, avoying dependences)
- Twisted matrix (I had no experience with it, but it looks much more
flexible/powerfull)

Zope provides you a specific framework, you have to match you application to
this framework, Zope (in my opinion) it is not a tool, it's an ambient.

It's seems that Edward it is new in the web oriented software, I think it has
a lot of potencialities and it will benefits Leo devellopment.

Please Edward, look at Zope as an example but not as THE options. Think about
what can be done, what should be done, and then we will take the best tool.

Anyway my opinion:
- SimpleHTTP server: usefull, it is in python, not very eficiente, just http
server	
- Medusa: usefull, very eficiente, just http server...
- Twisted Matrix: very powerfull, fresh comunity, confusing documentation, a
new paradigm, a devellopment tool.
- Zope: powerfull, eficient, comes with battery included, bad documentation,
to very paradigm oriented, the apps have to fit the paradigm, don't believe
all the promises, strong enthousiast comunity, poor web examples.


RodrigoB. 
#@-node:ekr.20031218072017.416:Other servers
#@+node:ekr.20031218072017.417:Is my ip public?
https://sourceforge.net/forum/message.php?msg_id=2007962
By: bwmulder

Since no one else answered this question, let me take a first take on the
question:

If you are connected to the internet, people can use your IP number to connect
to your computer. This IP number is often given dynamically, though some DSL
providers give you fixed IP numbers for an additional fee. If you did not ask
for fixed IP numbers, you probably have an dynamic IP number (I think).

An IP number consist of four digits. A connection to the (example) IP number
111.222.333.444 can by made via the request http://111.222.333.444

If you have a dynamic IP number, and your Internet provider provides you with
some space to publish HTML, you could, via a script, upload your current IP
number dynamically.

You might also consider buying a domain name. In this case, people can use the
domain name to connect to your computer instead of the IP number.

Another consideration are firewalls. Normally, you want a firewall isolating
your computer from attacks from the Internet. I firewall can be some additional
software. I am currently using a router, a piece of hardware, as a firewall.
Windows XP has firewall software build in. You might have to configure your
firewall to let requests for your server go through.

Finally, you might want to check the agreement you entered with your Internet
service provider, if you are allowed to run a server from your connection. It
might become a problem if your server becomes very popular.
#@-node:ekr.20031218072017.417:Is my ip public?
#@+node:ekr.20031218072017.418:Back ends for storing/retrieving nodes: Paul Paterson
Open Discussion
https://sourceforge.net/forum/message.php?msg_id=2009279
By: paulpaterson

What I see Zope offering is an alternative way of storing and retrieving nodes.
What you also get for "free" with Zope is concurrent access, security,
http/ftp/webdav access to the same node information etc. The hidden price you
pay is that Zope is big and many users will have other tools which can provide
these facilities also.

So, my thinking is that we can abstract the basic idea (alternative ways of
storing and retrieving node information) into Leo and then let the magic really
happen in the concrete implementation stage.

What does this mean? Well, we could change Leo so that whenever it goes to retrieve
Headline or Body it goes to a Node Server object to do that. The Node Server
object uses whatever method it wants to retrieve or set the information. The
Node server would also be responsible for telling Leo what child nodes an object
has and whether they are clones or not.

The cool part is that we could implement different kinds of Node server to talk
to different back-ends. These can then be thought of as drivers. So we might
have,

- a file system driver where all information is stored in files and directories
- a database driver where the DB stores all information
- an ftp driver
- a Zope driver
- the default Leo driver

People could write a driver to their own back end storage system. 

What is the advantage of this?

Well, the magic really happens in the back-end. If you choose a back end which
supports versioning, security, concurrent working, web access, etc etc then
Leo now supports them. If you choose a back-end which supports dynamic mark-up
or some other fancy stuff then Leo supports it. The key is that Leo doesn't
need to bind itself to any one system to achieve this - the end user can install
the relevant driver, configure the back-end and just go with it.

Paul
#@-node:ekr.20031218072017.418:Back ends for storing/retrieving nodes: Paul Paterson
#@+node:ekr.20031218072017.419:From Paul Paterson
Ok, I'll have a bash in a rough order or when things occurred...


1. Everything is web based. I had the same problem you did. I ran the
thing and said, "ok, so what did it do". Others have pointed you in the
right direction now with visiting http://localhost:8080 and
http://localhost:8080/manage to view the site and mange it respectively.

If you are running WinNT, 2000 or XP you can also run Zope as a service,
which is much more convenient as you don't need the console window open
all the time.


2. Everything in Zope is an object. Ok, you'll see this a lot. The best
thing to do is think "wow, cool" and then forget it again as you
probably wont really see how this helps at all until you get much deeper
into Zope. 


3. DTML allows you to construct web pages by piecing together bits much
like writing a program from functions. In fact you will find DTML is a
lot like tangling Leo's @root nodes. Here's a bit...

<!-- start html -->

<h>DTML allows you to assemble web pages much like Leo tangles
documents</h>

<p>For instance, have a look at how this page is constructed</p>

<dtml-var first_bit>
<dtml-var second_bit>
<dtml-var third_bit>

<!-- end html -->

The <dtml-var name> bit is like a < < name > > directive. It effectively
inserts the object (could be HTML, an image or something more complex)
in the current page. 

To see this snippet in action you can visit my server at
http://24.243.129.68:8080/members/sandbox/index_html

To see the code, visit http://24.243.129.68:8080/members/sandbox/manage
(username=edream, pwd=leo) and then click on the index_html to see the
main DTML. Feel free to mess around in here but please don't publish the
IP address as my ISP doesn't allow servers!


4. There is a lot of power in Zope products. Try going to www.zope.org
and seeing what is available. As an example I put a Wiki in the sandbox
area http://24.243.129.68:8080/members/sandbox/edswiki


5. If you are looking for a good book to begin with then steer clear of
"The Zope Book"! If you don't mind paying then "The book of Zope" is a
much better introduction. When you have read this then "The Zope Book"
will make some sense but really I found this book tremendously hard to
get through.


6. Web standards are very cool! Zope supports FTP. Point your favourite
FTP tool to,

ftp://24.243.129.68:8021/members/sandbox/

Or try using WebDav by creating a network place pointing to

http://24.243.129.68:8080/members/sandbox

You can then use windows explorer or an ftp tool to browse your objects.


7. Everything is an object! I can't do justice to the concept of
Acquisition here but by the time you have messed around with Zope a bit
you should start to see how acquisition starts to make things really
work like classes in Python. 


I realize this isn't very coherent - if I get a spare moment this
weekend I'll knock up a quick demo showing Leo interacting with Zope.

Regards,

Paul
#@-node:ekr.20031218072017.419:From Paul Paterson
#@-node:ekr.20031218072017.412:Zope
#@+node:ekr.20031218072017.420:Jabber
Open Discussion
https://sourceforge.net/forum/message.php?msg_id=2016634
By: jasonic

I have been thinking about LeoZopeWiki integration. I am a recovering Zope addict
[1999-2001] :-)  I believe Zope offers a very valuable client and server for
Leo.

I think Ed higlighted the distinction of collboration vs. sharing. So consdering
that re:  Leo and CVS , Leo and Zope, Leo and wikis, I had another idea this
morning..

LEO+JABBER

Jabber is an open XML-based  instant messaging and *presence* system. Although
Jabber is typically used for IM chat, its core designers have a much bigger
vision in mind.

Jabber Software Foundation
http://www.jabber.org/
O'Reilly Book
http://www.oreilly.com/catalog/jabber/
Python Jabber library
http://jabberpy.sourceforge.net/

CVS etc all depend on runing diff on posted static files which are checked in
or out. Clearly valuable, and good for __sharing__ but not so suitable as the
communication paradigm needed for collboration.

Wikis and Zope all suffer from problem of versioning and the time delay and
lack of timely communications to their cobtributors. There is no 'shared state'
or persistence in the collaboration beyond their own files or objectdatabases.

For example if two people want to edit a wiki or Zope site, they have an imeedaiet
problem of knowing whether or not the someone else is working one it already.

Score:
Sharing 1
Collaboration 0

Two  or more people wanting to edit a common project based on Leo have the same
dilemma. They can check the leo file into a wiki, Zope or CVS, but they still
don't have direct communication at teh content level.

score:
Sharing 1
Collaboration 0

PROPOSAL: LeoJabber
1. Integrate a Jabber client into Leo 
2. Add special Leo module to jabberd [Jabber's server daemon]

Leo-based developers could work in direct communication with each other allowing
them to add, edit and comment nodes in a shared le-space, local or remote. Static
publishing via upload/import etc all still apply.

LeoJabber would mean subscribing developers could immediately be aware of changes
and then apply whatever strategy is appropriate for handling them, such as:
 
a. autoUpdate()
b. makeNewNode()
c. runDiffFunctions()
d. notifyPartners()
e. notifyPublic()
etc..

Jabber via its presencing mechanism offers real-time and just-in time communcations.
If you are logged out, then mesages are queued.

An open Jabber message session is actually one long piece of XML data passed
over an XMLSocket :-) Sounds like a great fit for Leo

- All Jabber configs are XML.
- Good smart open source community.
- Similar open embracing philsophy as Leo
- Jabber connects diverse messaging systems., MSN, AOL etc [Most are
close/proprietary, though the trend is toward greater openness and connectivity]
- Many Jabber clients already. There is even one written in Flash so that any
webpage can participate.

Embedding Jabber in Leo would allow 'discussion' threads to  be integrated.
Developers need to bounce idea and notes around just as this forum does. But
often they need to be more provate or more focused on project specifics.
WORKFLOW 
It is important to know  which code is uptodate, but arguably, even *more* important
is to know which people and what discussions are uptodate. And if not, what
their status is. The larger, longer the more global the develpoment office/project,
the more this is true.

IM [instant messaging] are popular largely becuae they offer direct communication
with status feedback to crucial people's workflow:
"off-line", "on-line", "back-soon", "later" etc

Jabber extends this idea to create a platform for any presence application.
That is its long term-goal.

So in a Leo deevlopment project, that presence might apply to adding status
mesages such as
"making changes" "new version" "debugging" "review only" "major re-write"

or perhaps status/presence woudl be used for much lower level Leo-specific
purposes.

"new node"
"cloned to .."
"@file imported"
"version uploaded"
etc

I am not suggesting that Leo forget CVS or file upload storage. But I think
Jabber may truly provide the Missing Link, literally for Leo collaboration.

Jabber Software Foundation
http://www.jabber.org/
O'Reilly Book
http://www.oreilly.com/catalog/jabber/
Python Jabber library
http://jabberpy.sourceforge.net/

hope this makes sense
Jason
#@-node:ekr.20031218072017.420:Jabber
#@-node:ekr.20031218072017.404:LeoN, Zope & collaboration info
#@-node:ekr.20040706072605:Ideas for later...
#@+node:ekr.20040104162835.8:Mac notes: Dan Winkler
#@+node:ekr.20040104162835.9:Porting notes
Here's Apple's documentation on making Unix software run on OS X:

http://developer.apple.com/documentation/Porting/Conceptual/ 
PortingUnix/index.html
#@-node:ekr.20040104162835.9:Porting notes
#@+node:ekr.20040104162835.10:$Path, etc.
In general, Unix commands can go anywhere and they're found by the 
shell using the $PATH variable.  To know what your path is, type "echo 
$PATH" at the shell.

Typically you'll have new things added to your path by a file called 
.login in your home directory.  This runs when you log in and then the 
settings are inherited by all the shells you run.

You can also type the full path to something if you want to invoke it 
that way, such as "/usr/local/bin/python".

Fink puts everything underneath /sw so as to avoid conflicting with 
Apple's versions of things.

If you can't invoke a file, it might be that it's not set to be 
executable.  If you do "ls -l" you'll see files listed with their 
permissions.  You'll see some of r, w, and x meaning read, write and 
execute.  These appear three times for owner, group, and everyone.  You 
can do "chmod +x filename" to make it executable for the owner or you 
can use numbers as in "chmod 755 file name" which sets rwx for the 
owner (7 = 111 in binary = rwx) and rx for group and everyone (5 = 101 
in binary = r_x).

I know this might seem confusing at first but the fact that things 
won't execute without being set executable is a big curb on viruses.  
In fact, there are no OS X viruses yet.  Anyway, it's all a matter of 
what you're used to.  Windows seems confusing to someone new to it too.

#@-node:ekr.20040104162835.10:$Path, etc.
#@+node:ekr.20040104162835.11:which python
You can type "which python" to find out which version of python (or any 
other command) will run.
#@-node:ekr.20040104162835.11:which python
#@+node:ekr.20040104162835.12:get info
That error message (from import _tkinter) makes it sound like you are 
somehow running the text-only version of Python that came with OS X... 
except you said you deleted that.

You can use "get info" in the finder to check and set which program 
will be used to open a given file.  So you can select your main leo.py 
file (or whichever the one you start with is), do get info on it, and 
tell it to open with the MacPython launcher that you want.  Then you 
should be able to double click it to open it.  That's what I do to run 
Leo on my Mac.

#@-node:ekr.20040104162835.12:get info
#@+node:ekr.20040104162835.13:Fink & aqua
Yes, fink does have pre-built Pythons, both 2.1 and 2.2.  (If you don't 
see them it probably means you don't have the right servers listed in 
your /sw/etc/apt/sources.list file.)  However, the versions of Python 
you'd get through fink are set up to run under X Windows, which I don't 
think is what you want.

I think what you want is MacPython which can run Tk programs like Leo 
under Aqua.  That's what I use these days.

I can tell from your question that you don't understand the following 
differences between the versions of Python available:

1) The version that comes with OS X is a text only one which doesn't 
have Tk.  Leo can't run under that.  Also, I hate Apple for including 
this instead of one that does have Tk and I hope they'll fix it some 
day.

2) You can get a version of Python from fink with has Tk but which runs 
under X Windows.  I don't think you want that.

3). You can also get MacPython which has Tk but it's a version of Tk 
that uses the Aqua windowing system, not X Windows.

So Tk can either be present or not and if it is present it can use 
either X Windows or Aqua.  You want it present and using Aqua, I think.


#@-node:ekr.20040104162835.13:Fink & aqua
#@+node:ekr.20040104162835.14:Mac, Fink, etc.
> 1. The python that FC installs is MacPython.  I think that because the
> MacPython docs talk about Fink.

Nope.  The python installed by FC knows nothing about the Mac.  It 
thinks it's running on a Unix machine.  And it uses a version of Tk 
which thinks it's running on a Unix machine.  The window standard on 
Unix is called X (or X11 or XFree86, all the same thing).  So the main 
reason to run Leo this way would be to get an idea of how it works for 
Unix/Linux users.  But when programs run under X, they don't look like 
Mac programs.  They don't get all those glossy, translucent widgets 
that Aqua provides.  They really look like they would on a Unix/Linux 
machine.

Aqua is the native windowing system on Mac.  MacPython is set up to 
work with it.  Most Mac users will want Leo to work this way.  That's 
what I do.

>
>
> I have the TkTclAquBI (Batteries included) installer.  Is installing 
> this
> enough to get Leo to work with Aqua?  Do I have to de-install the
> present tk stuff that I installed with FC?

Yes, I think that's all I installed to get Tk to work under Aqua.  You 
don't have to deinstall the FC stuff.  All the FC stuff lives in its 
own world under /sw and runs under X.  It won't conflict with the Mac 
world.

#@-node:ekr.20040104162835.14:Mac, Fink, etc.
#@+node:ekr.20040104162835.15:Double clicking on Linux
Double-clickable things (i.e. Macintosh applications) are usually 
actually folders with a name that ends in .app.  The file you found is 
probably executable only from the command line, not by double clicking 
it.  So I think if you run it from the command line it will work but 
will not know about Tk because Apple's version was built without Tk 
support.

You can also execute the .app programs from the command line by using 
the open command, so "open foo.app" will do the same thing as double 
clicking on foo in the finder (the .app extension is suppressed).  The 
idea behind this is that an application can look like just one opaque 
icon in the finder but actually have all its resources nicely organized 
in subfolders.
#@-node:ekr.20040104162835.15:Double clicking on Linux
#@+node:ekr.20040104162835.16:Getting Leo on Fink Commander
FC gets its list of packages from the servers listed in 
/sw/etc/apt/sources.list.  So you can put Leo into any server and 
people can add it to their sources.list or you can talk to the people 
who run the default servers and get Leo hosted there (better).
#@-node:ekr.20040104162835.16:Getting Leo on Fink Commander
#@-node:ekr.20040104162835.8:Mac notes: Dan Winkler
#@+node:ekr.20031218072017.421:Early Milestones
#@+node:ekr.20031218072017.422:02/03/02 Leo 0.08 released
#@-node:ekr.20031218072017.422:02/03/02 Leo 0.08 released
#@+node:ekr.20031218072017.423:12/17/01 ** Leo 0.05 released
#@-node:ekr.20031218072017.423:12/17/01 ** Leo 0.05 released
#@+node:ekr.20031218072017.424:12/16/01 Leo becomes functional
leo.py reads and writes exactly like LeoCB
#@nonl
#@-node:ekr.20031218072017.424:12/16/01 Leo becomes functional
#@+node:ekr.20031218072017.425:12/13/01 Syntax coloring works
Amazing.  I wrote some dummy code last night, read up on indices this morning, and got everything to work in a couple of hours. The result is very fast: no optimization is needed for Leo. I love Tkinter!

Added c.recolor and tree.recolor routines.  This hooks should be called whenever the body text changes.  Apparently there is no "OnTextChanged" event in Tk.
#@nonl
#@-node:ekr.20031218072017.425:12/13/01 Syntax coloring works
#@+node:ekr.20031218072017.426:12/09/01 Tree now drawn properly
#@-node:ekr.20031218072017.426:12/09/01 Tree now drawn properly
#@+node:ekr.20031218072017.427:12/05/01 Tree works with Tkinter
#@-node:ekr.20031218072017.427:12/05/01 Tree works with Tkinter
#@+node:ekr.20031218072017.428:11/10/01 ** began conversion to tk
This marked my complete frustration with wxLeo and wxPython, and the real beginning of the work on leo.py.
#@nonl
#@-node:ekr.20031218072017.428:11/10/01 ** began conversion to tk
#@+node:ekr.20031218072017.429:10/26/01 First successful read of .leo file w/ @file nodes
#@-node:ekr.20031218072017.429:10/26/01 First successful read of .leo file w/ @file nodes
#@+node:ekr.20031218072017.430:9/29/01 c2py: Totally in love with Python
I am totally in love with Python.  Everything is so much easier:  Automatic debugging, no declarations, no types, no compilation. Great data structures. Even without single stepping the debugging is easy.

All major aspects of c2py are now complete.
#@nonl
#@-node:ekr.20031218072017.430:9/29/01 c2py: Totally in love with Python
#@+node:ekr.20031218072017.431:ca. 9/1/01 began work on wxPython version of Leo
I am not sure exactly when this happened.  The details apparently have been lost.  There was a time when I was experimenting with Python and wxPython, and a time when I was working on wxWindows version of Leo.
#@nonl
#@-node:ekr.20031218072017.431:ca. 9/1/01 began work on wxPython version of Leo
#@-node:ekr.20031218072017.421:Early Milestones
#@+node:ekr.20031218072017.434:Unused code
@ignore
@language python
@color
#@nonl
#@+node:EKR.20040505090056:From perfect import script
@ignore
#@nonl
#@+node:EKR.20040505090056.1:class sentinel_squasher
class sentinel_squasher:
	"""
	The heart of the script.
	
	Creates files without sentinels from files with sentinels.
	
	Propagates changes in the files without sentinels back
	to the files with sentinels.
	
	"""

@others
#@nonl
#@+node:EKR.20040505090056.2:report_mismatch
# was check_lines_for_equality

def report_mismatch (self,lines1,lines2,message,lines1_message,lines2_message):

	"""
	Generate a report when something goes wrong.
	"""

	print '='*20
	print message
	
	if 0:
		print lines1_message
		print '-'*20
		for line in lines1:
		  print line,

		print '='*20
	
		print lines2_message
		print '-'*20
		for line in lines2:
			print line,
			
	print "length of files",len(lines1),len(lines2)
	
	if len(lines1) == len(lines2):
		i = 0
		while 1:
			if lines1[i] != lines2[i]:
				print "first mismatched lines:"
				print lines1[i]
				print lines2[i]
				break
			i += 1
#@nonl
#@-node:EKR.20040505090056.2:report_mismatch
#@+node:EKR.20040505090056.3:create_mapping
def create_mapping (self,lines,marker):
	"""

	'lines' is a list of lines of a file with sentinels.
 
	Returns:

	result: lines with all sentinels removed.

	mapping: a list such that result[mapping[i]] == lines[i]
	for all i in range(len(result))

	"""

	mapping = [] ; result = []
	for i in xrange(len(lines)):
		line = lines[i]
		if not is_sentinel(line,marker):
			result.append(line)
			mapping.append(i)

	# Create a last mapping entry for copy_sentinels.
	mapping.append(i)

	return result, mapping
#@nonl
#@-node:EKR.20040505090056.3:create_mapping
#@+node:EKR.20040505090056.4:old code
#@+node:EKR.20040505090056.5:OLDcopy_sentinels
@ Sentinels are NEVER deleted by this script.

If code is replaced, or deleted, then we must make sure that the sentinels are still in the Leo file.

We detect sentinel lines by checking for gaps in the mapping.
@c

def OLDcopy_sentinels (self,writer,leo_reader,mapping,startline,endline):
	"""
	
	Copy lines from leo_reader to writer if those lines contain sentinels.

	Copy all sentinels after the current reader postion up to,
	but not including, mapping[endline].

	"""

	j_last = mapping[startline]
	i = startline + 1
	while i <= endline:
		j = mapping[i]
		if j_last + 1 != j:
			leo_reader.sync(j_last + 1)
			# Copy the deleted sentinels that comprise the gap.
			while leo_reader.index() < j:
				line = leo_reader.get()
				if testing: print "Copy sentinels:", line,
				writer.push(line)
		j_last = j ; i += 1

	leo_reader.sync(mapping[endline])
#@nonl
#@-node:EKR.20040505090056.5:OLDcopy_sentinels
#@+node:EKR.20040505090056.6:OLDpull_source
def pull_source(self, sourcefile, targetfile):
	"""

	Propagate the changes of targetfile back to sourcefile.
	sourcefile has sentinels, and targetfile does not.

	This is the heart of the script.

	"""
	print testing
	if testing: g.trace(sourcefile,targetfile)
	<< init pull_source vars >>
	<< establish the loop invariant >>
	for tag, i1, i2, j1, j2 in matcher.get_opcodes():
		if testing:
			print ; print "opcode",tag,i1,i2,j1,j2 ; print
		<< update and check the loop invariant >>
		if tag == 'equal':
			<< handle 'equal' tag >>
		elif tag == 'replace':
			<< handle 'replace' tag >>
		elif tag == 'delete':
			<< handle 'delete' tag >>
		elif tag == 'insert':
			<< handle 'insert' tag >>
		else: assert 0
	<< copy the sentinels at the end of the file >>
	written = write_if_changed(writer.getlines(),targetfile,sourcefile)
	if written:
		<<final paranoia check>>
#@+node:EKR.20040505090056.7:<< init pull_source vars >>
marker = marker_from_extension(sourcefile) # The sentinel comment marker.
	
sourcelines = file(sourcefile).readlines() # Has sentinels.
targetlines = file(targetfile).readlines() # No sentinels.

strippedSourceLines,mapping = self.create_mapping(sourcelines,marker)

writer = sourcewriter() # Accumulates the new file.
i_reader = sourcereader(strippedSourceLines) # Unmodified file, no sentinels.
j_reader = sourcereader(targetlines) # Modified file, no sentinels.
leo_reader = sourcereader(sourcelines) # The file with sentinels.

matcher = difflib.SequenceMatcher(None,strippedSourceLines,targetlines)
#@nonl
#@-node:EKR.20040505090056.7:<< init pull_source vars >>
#@+node:EKR.20040505090056.8:<<establish the loop invariant>>
@ 
We compare the 'targetlines' with 'strippedSourceLines' and propagate the
changes back into 'writer' while making sure that all sentinels of 'sourcelines'
are copied as well.

The loop invariant is that all three readers are in sync. Also, writer has
accumulated the new file, which is going to replace leo_reader.
@c

# Check that all ranges returned by get_opcodes() are contiguous
i2_old = j2_old = -1

# Copy the sentinels at the beginning of the file.
while leo_reader.index() < mapping[0]:
	line = leo_reader.get()
	writer.push(line)
#@nonl
#@-node:EKR.20040505090056.8:<<establish the loop invariant>>
#@+node:EKR.20040505090056.9:<< update and check the loop invariant>>
# We need the ranges returned by get_opcodes to completely cover the source lines being compared.
# We also need the ranges not to overlap.
if i2_old != -1:
	assert i2_old == i1
	assert j2_old == j1
i2_old = i2 ; j2_old = j2

@ Loosely speaking, the loop invariant is that we have processed everything up to,
but not including, the lower bound of the ranges returned by the iterator.

We have to check the three readers, i_reader, j_reader, and leo_reader. For the
writer, the filter must reproduce the modified file up until, but not including,
j1. In addition, all the sentinels of the original Leo file, up until
mapping[i1], must be present in the new_source_file.

@code

# Check the loop invariant.
assert i_reader.i == i1
assert j_reader.i == j1
assert leo_reader.i == mapping[i1]
if testing: # A bit costly.
	t_sourcelines,t_sentinel_lines = push_filter_lines(writer.lines, marker)
	# Check that we have all the modifications so far.
	assert t_sourcelines == j_reader.lines[:j1]
	# Check that we kept all sentinels so far.
	assert t_sentinel_lines == push_filter_lines(leo_reader.lines[:leo_reader.i], marker)[1]
#@nonl
#@-node:EKR.20040505090056.9:<< update and check the loop invariant>>
#@+node:EKR.20040505090056.10:<< handle 'equal' tag >>
# nothing is to be done.  Leave the Leo file alone.
# Copy the lines from the leo file to the new sourcefile.
# This loop copies both text and sentinels.
while leo_reader.index() <= mapping[i2 - 1]:
	line = leo_reader.get()
	if 0:
		if testing: print "Equal: ", line,
	writer.push(line)

if testing:
	print "Equal: synch i", i_reader.i, i2
	print "Equal: synch j", j_reader.i, j2

i_reader.sync(i2)
j_reader.sync(j2)

# now we must copy the sentinels which might follow the lines which were equal.       
self.copy_sentinels(writer,leo_reader,mapping, i2 - 1, i2)
#@nonl
#@-node:EKR.20040505090056.10:<< handle 'equal' tag >>
#@+node:EKR.20040505090056.11:<< handle 'replace' tag >>
@ Replace lines that may span sentinels.

For now, we put all the new contents after the first sentinels.

A more complex approach: run the difflib across the different lines and try to
construct a mapping changed line => orignal line.
@c

while j_reader.index() < j2:
	line = j_reader.get()
	if testing: print "Replace:", line,
	writer.push(line)

# Copy the sentinels which might be between the changed code.         
self.copy_sentinels(writer,leo_reader,mapping,i1,i2)
i_reader.sync(i2)
#@nonl
#@-node:EKR.20040505090056.11:<< handle 'replace' tag >>
#@+node:EKR.20040505090056.12:<< handle 'delete' tag >>
# We have to delete lines.
# However, we NEVER delete sentinels, so they must be copied over.

if testing:
	print "Delete: synch i", i_reader.i, i1
	print "Delete: synch j", j_reader.i, j1
	
# sync the readers
j_reader.sync(j2)
i_reader.sync(i2)

self.copy_sentinels(writer, leo_reader, mapping, i1, i2)
#@nonl
#@-node:EKR.20040505090056.12:<< handle 'delete' tag >>
#@+node:EKR.20040505090056.13:<< handle 'insert' tag >>
while j_reader.index() < j2:
	line = j_reader.get()
	if testing: print "insert: ", line,
	writer.push(line)

# Since (only) lines are inserted, we do not have to reposition any reader.
#@nonl
#@-node:EKR.20040505090056.13:<< handle 'insert' tag >>
#@+node:EKR.20040505090056.14:<< copy the sentinels at the end of the file >>
while leo_reader.index() < leo_reader.size():
	line = leo_reader.get()
	writer.push(line)
	if testing: print "Copy last line",line
#@nonl
#@-node:EKR.20040505090056.14:<< copy the sentinels at the end of the file >>
#@+node:EKR.20040505090056.15:<<final paranoia check>>
@ For the initial usage, we check that the output actually makes sense.
	We check two things:
	1. Applying a 'push' operation will produce the modified file.
	2. Our new sourcefile still has the same sentinels as the replaced one.
@c

s_outlines,sentinel_lines = push_filter(sourcefile)

# Check that 'push' will re-create the changed file.
if s_outlines != targetlines:
	self.report_mismatch(s_outlines, targetlines,
		"Pull did not work as expected",
		"Content of sourcefile:",
		"Content of modified file:")

# Check that no sentinels got lost.
old_sentinel_lines = push_filter_lines(leo_reader.lines[:leo_reader.i], marker)[1]
if sentinel_lines != old_sentinel_lines:
	self.report_mismatch(sentinel_lines, old_sentinel_lines,
		"Pull modified sentinel lines:",
		"Current sentinel lines:",
		"Old sentinel lines:")
#@nonl
#@-node:EKR.20040505090056.15:<<final paranoia check>>
#@-node:EKR.20040505090056.6:OLDpull_source
#@-node:EKR.20040505090056.4:old code
#@+node:EKR.20040505090056.16:pull_source
def pull_source(self,sourcefile,targetfile):
	"""

	Propagate the changes of targetfile back to sourcefile.
	sourcefile has sentinels, and targetfile does not.

	"""
	if testing: g.trace(sourcefile,targetfile)
	<< init pull_source vars >>
	<< establish the loop invariant >>
	for tag, i1, i2, j1, j2 in matcher.get_opcodes():
		if testing:
			print ; print "Opcode",tag,i1,i2,j1,j2 ; print
		<< update and check the loop invariant >>
		if tag == 'equal':
			<< handle 'equal' tag >>
		elif tag == 'replace':
			<< handle 'replace' tag >>
		elif tag == 'delete':
			<< handle 'delete' tag >>
		elif tag == 'insert':
			<< handle 'insert' tag >>
		else: assert 0,"bad tag"
	<< copy the sentinels at the end of the file >>
	written = write_if_changed(write_lines,targetfile,sourcefile)
	if written:
		<<final paranoia check>>
#@+node:EKR.20040505090056.17:<< init pull_source vars >>
marker = marker_from_extension(sourcefile) # The sentinel comment marker.

sourceLines = file(sourcefile).readlines() # Has sentinels.
targetLines = file(targetfile).readlines() # No sentinels.
strippedSourceLines,mapping = self.create_mapping(sourceLines,marker)

write_lines = []
i_lines = strippedSourceLines
j_lines = targetLines
fat_lines = sourceLines
i_pos = j_pos = fat_pos = 0

matcher = difflib.SequenceMatcher(None,strippedSourceLines,targetLines)
#@nonl
#@-node:EKR.20040505090056.17:<< init pull_source vars >>
#@+node:EKR.20040505090056.18:<<establish the loop invariant>>
@
We compare the 'targetLines' with 'strippedSourceLines' and propagate the
changes back into 'write_lines' while making sure that all sentinels of 'sourceLines'
are copied as well.
@c

# Check that all ranges returned by get_opcodes() are contiguous
i2_old = j2_old = -1

# Copy the sentinels at the beginning of the file.
while fat_pos < mapping[0]:
	line = fat_lines[fat_pos]
	write_lines.append(line)
	if testing: print "copy initial line",fat_pos,line
	fat_pos += 1
#@nonl
#@-node:EKR.20040505090056.18:<<establish the loop invariant>>
#@+node:EKR.20040505090056.19:<< update and check the loop invariant>>
# We need the ranges returned by get_opcodes to completely cover the source lines being compared.
# We also need the ranges not to overlap.
if i2_old != -1:
	assert i2_old == i1,"i2_old==i1"
	assert j2_old == j1,"j2_old==j1"

i2_old = i2 ; j2_old = j2

# Check the loop invariants.
assert i_pos == i1,"i_pos==i1"
assert j_pos == j1,"j_pos==j1"
assert fat_pos == mapping[i1],"fat_pos == mapping[i1]"

if 0: # not yet.
	if testing: # A bit costly.
		t_sourcelines,t_sentinel_lines = push_filter_lines(write_lines, marker)
		# Check that we have all the modifications so far.
		assert t_sourcelines == j_lines[:j1],"t_sourcelines == j_lines[:j1]"
		# Check that we kept all sentinels so far.
		assert t_sentinel_lines == push_filter_lines(fat_lines[:fat_pos], marker)[1]
#@nonl
#@-node:EKR.20040505090056.19:<< update and check the loop invariant>>
#@+node:EKR.20040505090056.20:<< handle 'equal' tag >>
# nothing is to be done.  Leave the Leo file alone.
# Copy the lines from the leo file to the new sourcefile.
# This loop copies both text and sentinels.

# while leo_reader.index() <= mapping[i2 - 1]:
while fat_pos <= mapping[i2-1]:
	line = fat_lines[fat_pos]
	if 0:
		if testing: print "Equal: copying ", line,
	write_lines.append(line) # writer.push(line)
	fat_pos += 1

if testing:
	print "Equal: synch i", i_pos,i2
	print "Equal: synch j", j_pos,j2

i_pos = i2
j_pos = j2

# Copy the sentinels which might follow the lines.       
fat_pos = self.copy_sentinels(write_lines,fat_lines,fat_pos,mapping,i2-1,i2)
#@nonl
#@-node:EKR.20040505090056.20:<< handle 'equal' tag >>
#@+node:EKR.20040505090056.21:<< handle 'replace' tag >>
@ Replace lines that may span sentinels.

For now, we put all the new contents after the first sentinels.

A more complex approach: run the difflib across the different lines and try to
construct a mapping changed line => orignal line.
@c

while j_pos < j2:
	line = j_lines[j_pos]
	if testing: print "Replace:", line,
	write_lines.append(line)
	j_pos += 1

# Copy the sentinels which might be between the changed code.         
fat_pos = self.copy_sentinels(write_lines,fat_lines,fat_pos,mapping,i1,i2)
i_pos = i2
#@nonl
#@-node:EKR.20040505090056.21:<< handle 'replace' tag >>
#@+node:EKR.20040505090056.22:<< handle 'delete' tag >>
if testing:
	print "delete: i",i_pos,i1
	print "delete: j",j_pos,j1
	
# Synch the import streams.
j_pos = j2 
i_pos = i2

# Restore any deleted sentinels.
fat_pos = self.copy_sentinels(write_lines,fat_lines,fat_pos,mapping,i1,i2)
#@nonl
#@-node:EKR.20040505090056.22:<< handle 'delete' tag >>
#@+node:EKR.20040505090056.23:<< handle 'insert' tag >>
while j_pos < j2:
	line = j_lines[j_pos]
	if testing: print "Insert:", line,
	write_lines.append(line)
	j_pos += 1

# We do not have to reposition any input stream.
#@nonl
#@-node:EKR.20040505090056.23:<< handle 'insert' tag >>
#@+node:EKR.20040505090056.24:<< copy the sentinels at the end of the file >>
while fat_pos < len(fat_lines):
	line = fat_lines[fat_pos]
	write_lines.append(line)
	if testing: print "appending last line",line
	fat_pos += 1
#@nonl
#@-node:EKR.20040505090056.24:<< copy the sentinels at the end of the file >>
#@+node:EKR.20040505090056.25:<<final paranoia check>>
# Check that 'push' will re-create the changed file.
strippedLines,sentinel_lines = push_filter(sourcefile)

if strippedLines != targetLines:
	self.report_mismatch(strippedLines, targetLines,
		"Pull did not work as expected",
		"Content of sourcefile:",
		"Content of modified file:")

# Check that no sentinels got lost.
old_strippedLines,old_sentinel_lines = push_filter_lines(sourceLines, marker)

if sentinel_lines != old_sentinel_lines:
	self.report_mismatch(sentinel_lines, old_sentinel_lines,
		"Pull modified sentinel lines:",
		"Current sentinel lines:",
		"Old sentinel lines:")
#@nonl
#@-node:EKR.20040505090056.25:<<final paranoia check>>
#@-node:EKR.20040505090056.16:pull_source
#@+node:EKR.20040505090056.26:copy_sentinels
@ This script retains _all_ sentinels in the fat file.  If lines are replaced, or deleted,
we restore deleted sentinel lines by checking for gaps in the mapping.
@c

def copy_sentinels (self,write_lines,fat_lines,fat_pos,mapping,startline,endline):
	"""
	
	Copy sentinel lines from fat_lines to write_lines.

	Copy all sentinels _after_ the current reader postion up to,
	but not including, mapping[endline].

	"""

	j_last = mapping[startline]
	i = startline + 1
	while i <= endline:
		j = mapping[i]
		if j_last + 1 != j:
			fat_pos = j_last + 1
			# Copy the deleted sentinels that comprise the gap.
			while fat_pos < j:
				line = fat_lines[fat_pos]
				write_lines.append(line)
				if testing: print "Copy sentinels:",fat_pos,line,
				fat_pos += 1
		j_last = j ; i += 1

	fat_pos = mapping[endline]
	return fat_pos
#@nonl
#@-node:EKR.20040505090056.26:copy_sentinels
#@-node:EKR.20040505090056.1:class sentinel_squasher
#@+node:EKR.20040505090056.27:class sourcereader
class sourcereader:
	"""
	A simple class to read lines sequentially.
	
	The class keeps an internal index, so that each
	call to get returns the next line.
	
	Index returns the internal index, and sync
	advances the index to the the desired line.
	
	The index is the *next* line to be returned.
	
	The line numbering starts from 0.
	
	"""

@others
#@+node:EKR.20040505090056.28:__init__
def __init__(self, lines):
	self.lines = lines
	self.length = len(self.lines)
	self.i = 0
#@-node:EKR.20040505090056.28:__init__
#@+node:EKR.20040505090056.29:index
def index(self):
	return self.i
#@-node:EKR.20040505090056.29:index
#@+node:EKR.20040505090056.30:get
def get(self):
	result = self.lines[self.i]
	self.i += 1
	return result
#@nonl
#@-node:EKR.20040505090056.30:get
#@+node:EKR.20040505090056.31:sync
def sync(self, i):
	self.i = i
#@-node:EKR.20040505090056.31:sync
#@+node:EKR.20040505090056.32:size
def size(self):
	return self.length
#@-node:EKR.20040505090056.32:size
#@+node:EKR.20040505090056.33:atEnd
def atEnd(self):
	return self.index >= self.length
#@nonl
#@-node:EKR.20040505090056.33:atEnd
#@-node:EKR.20040505090056.27:class sourcereader
#@+node:EKR.20040505090056.34:class sourcewriter
class sourcewriter:
	
	"""
	Convenience class to capture output to a file.
	"""

@others


#@+node:EKR.20040505090056.35:__init__
def __init__(self):
	self.i = 0
	self.lines = []
#@-node:EKR.20040505090056.35:__init__
#@+node:EKR.20040505090056.36:push
def push(self, line):
	self.lines.append(line)
	self.i += 1
#@-node:EKR.20040505090056.36:push
#@+node:EKR.20040505090056.37:index
def index(self):
	return self.i
#@-node:EKR.20040505090056.37:index
#@+node:EKR.20040505090056.38:getlines
def getlines(self):
	return self.lines
#@-node:EKR.20040505090056.38:getlines
#@-node:EKR.20040505090056.34:class sourcewriter
#@+node:EKR.20040505090056.39:copy_time
def copy_time(sourcefilename, targetfilename):
	
	"""
	Set the modification time of target file to the
	modification time of sourcefile.
	"""

	st = os.stat(sourcefilename)

	if hasattr(os, 'utime'):
		os.utime(targetfilename, (st.st_atime, st.st_mtime))
	elif hasattr(os, 'mtime'):
		os.mtime(targetfilename, st.st_mtime)
	else:
		print "copy_time can not set file modification time."
#@nonl
#@-node:EKR.20040505090056.39:copy_time
#@+node:EKR.20040505090056.40:create_ext
def create_ext(extensions=('.py', '.c', '.cpp', '.h', '.bat'), directory=".", sourcedir=None):
	"""
	Convenience script: calls create_leo_subdirectory for all files in 'directory' with an extension in 'extensions'.
	
	NOTE THAT IF BOTH A DIRECTORY AND A SOURCEDIR ARE SPECIFIED, THIS SCRIPT WILL DELETE THE WHOLE DIRECTORY 'directory'.
	
	"""
	if sourcedir:
		# For quick testing, we make a copy of a directory.
		if os.path.exists(directory):
			shutil.rmtree(directory)
		shutil.copytree(sourcedir, directory)

		# Not sure if this is necessary, but let's delete all .pyc files
		map(os.unlink, [os.path.join(root, filename) 
			for root, dirs, files in os.walk(directory) 
				for filename in files if os.path.splitext(filename)[1] == '.pyc'])
				
	files = [f for f in os.listdir(directory) if os.path.splitext(f)[1] in extensions]
	create_leo_subdirectory (files, directory)
#@nonl
#@-node:EKR.20040505090056.40:create_ext
#@+node:EKR.20040505090056.41:create_leo_subdirectory
def create_leo_subdirectory(files, directory="."):
	"""
	Moves 'files' into a Leo subdirectory.
	
	'files' are replaced with files without sentinels.
	
	files is the list of files which should be shuffled to the subdirectory.
	
	- Checks if a Leo subdirectory exists. If yes, does nothing.
	
	- Moves the files to the Leo subdirectory.
	
	- Creates files without sentinels in the original directory.
	"""
	from os.path import exists, join, split, splitext
	assert exists(directory)
	targetfiles = [join(directory,element) for element in files]
	missing_files = [filename for filename in targetfiles if not exists(filename)]
	assert len(missing_files) == 0,"Files do not exist:%s" % missing_files
		
	leo_directory = join(directory, "Leo")
	if exists(leo_directory):
		print "Directory already exists. Exit"
		return
	os.mkdir(leo_directory)
		
	pairs = [split(filename) for filename in targetfiles]
	sourcefiles = [join(dir, 'Leo', name) for dir, name in pairs]
	full_filenames = zip(sourcefiles, targetfiles)
	for targetfile, sourcefile in full_filenames: os.rename(sourcefile, targetfile)
	push(full_filenames) 
#@-node:EKR.20040505090056.41:create_leo_subdirectory
#@+node:EKR.20040505090056.42:is_sentinel
def is_sentinel(line, marker):
	"""
	Check if line starts with a Leo marker.
	
	Leo markers are filtered away by this script.
	
	Leo markers start with a comment character, which dependends
	on the language used. That's why the marker is passed in.
	"""
	return line.lstrip().startswith(marker)
#@nonl
#@-node:EKR.20040505090056.42:is_sentinel
#@+node:EKR.20040505090056.43:marker_from_extension
def marker_from_extension(filename):
	"""
	Tries to guess the sentinel leadin
	comment from the filename extension.
	
	This code should probably be shared
	with the main Leo code.
	"""
	root, ext = os.path.splitext(filename)
	if ext == '.tmp':
		root, ext = os.path.splitext(root)
	if ext in ('.h', '.c'):
		marker = "//@"
	elif ext in (".py", ".cfg", ".bat", ".ksh"):
		marker = "#@"
	else:
		assert 0, "extension %s not handled by this plugin" % ext
	return marker
#@nonl
#@-node:EKR.20040505090056.43:marker_from_extension
#@+node:EKR.20040505090056.44:push_file
def push_file(sourcefilename, targetfilename):
	
	outlines, sentinel_lines = push_filter(sourcefilename)
	write_if_changed(outlines, sourcefilename, targetfilename)
#@nonl
#@-node:EKR.20040505090056.44:push_file
#@+node:EKR.20040505090056.45:push_filter
def push_filter(sourcefilename):
	"""
	
	Removes sentinels from the lines of 'sourcefilename'.
	
	"""

	return push_filter_lines(
		file(sourcefilename).readlines(),
		marker_from_extension(sourcefilename))
#@-node:EKR.20040505090056.45:push_filter
#@+node:EKR.20040505090056.46:push_filter_lines
def push_filter_lines(lines, marker):
	"""
	
	Removes sentinels from lines.
	
	"""

	result = [] ; sentinel_lines = []
	for line in lines:
		if is_sentinel(line, marker):
			sentinel_lines.append(line)
		else:
			result.append(line)

	return result, sentinel_lines
#@nonl
#@-node:EKR.20040505090056.46:push_filter_lines
#@+node:EKR.20040505090056.47:write_if_changed
def write_if_changed(lines, sourcefilename, targetfilename):
	"""
	
	Replaces target file if it is not the same as 'lines',
	and makes the modification date of target file the same as the source file.
	
	Optionally backs up the overwritten file.

	"""
	
	copy = not os.path.exists(targetfilename) or lines != file(targetfilename).readlines()
		
	if testing:
		if copy:
			print "Copying", sourcefilename, "to", targetfilename, "without sentinals"
		else:
			print "files are identical"

	if copy:
		if do_backups:
			<< make backup file >>
		outfile = open(targetfilename, "w")
		for line in lines:
			outfile.write(line)
		outfile.close()
		copy_time(sourcefilename,targetfilename)
	return copy
#@+node:EKR.20040505090056.48:<< make backup file >>
# Keep the old file around while we are debugging this script
if os.path.exists(targetfilename):
	count = 0
	backupname = "%s.~%s~" % (targetfilename, count)
	while os.path.exists(backupname):
		count += 1
		backupname = "%s.~%s~" % (targetfilename, count)
	os.rename(targetfilename, backupname)
	if testing:
		print "backup file in ", backupname
#@nonl
#@-node:EKR.20040505090056.48:<< make backup file >>
#@-node:EKR.20040505090056.47:write_if_changed
#@-node:EKR.20040505090056:From perfect import script
#@+node:ekr.20040301201418:c.convertTreeToSharedNodes (for conversion)
# WARNING: this only works if not g.sharedNodes.

def convertTreeToSharedNodes(self):

	c = self
	
	# Return if the tree has already been converted.
	v = c.rootVnode()
	while v:
		if v._firstChild and not v._firstChild._parent:
			# print ; print "already converted"
			return
		v = v.threadNext()

	# Init.
	v = c.rootVnode()
	while v:
		v.t.vnodeList = []
		v = v.threadNext()
		
	# Create a list of cloned nodes:
	v = c.rootVnode() ; cloneList = []
	while v:
		if v.isCloned():
			# print "clone",v
			cloneList.append(v)
		v = v.threadNext()

	# Set _firstChild in tnodes.
	v = c.rootVnode()
	while v:
		child = v.firstChild()
		# Careful: set the field only the first time we see a shared tree.
		# This logic must match the logic below.
		if child:
			if not hasattr(v.t,"_firstChild"):
				v.t._firstChild = child
		else: v.t._firstChild = None
		v = v.threadNext()
		
	v = c.rootVnode()
	while v:
		if child and not hasattr(v.t,"_firstChild"):
			v.t._firstChild = child
		v = v.threadNext()
		
	# Set v.t.vnodeList.
	v = c.rootVnode()
	while v:
		# Careful: only set one value for non-cloned joined nodes.
		if v in cloneList: # Cloned
			try:    v.t.vnodeList.append(v)
			except: v.t.vnodeList = [v]
		elif not hasattr(v.t,"vnodeList"): # Maybe joined.
			v.t.vnodeList = [v]
		v = v.threadNext()
		
	# Clear _parent field of any node whose parent is a clone.
	v = c.rootVnode() ; clearList = []
	for v in cloneList:
		child = v.firstChild()
		while child:
			clearList.append(child)
			child = child.next()

	for v in clearList:
		v._parent = None
#@nonl
#@-node:ekr.20040301201418:c.convertTreeToSharedNodes (for conversion)
#@+node:ekr.20031218072017.3380:v.edit_text
def edit_text (self):

    v = self ; c = v.c ; p = c.currentPosition()
    
    g.trace("ooooops")
    #import traceback ; traceback.print_stack()
    
    pairs = self.c.frame.tree.getEditTextDict(v)
    for p2,t2 in pairs:
        if p.equal(p2):
            # g.trace("found",t2)
            return t2
            
    return None
#@nonl
#@-node:ekr.20031218072017.3380:v.edit_text
#@-node:ekr.20031218072017.434:Unused code
#@-all
#@nonl
#@-node:ekr.20031218072017.329:@thin ../doc/leoNotes.txt
#@-leo
