.. @+leo-ver=5-thin
.. @+node:ekr.20100119205347.6015: * @file ../doc/leoToDo.txt
.. @@language rest # override the default .txt coloring.

.. @+all
.. @+node:ekr.20131105020211.18058: ** Important
.. @+node:ekr.20131106061848.16384: *3* * Create github repo
.. @+node:ekr.20131027064821.18693: *3* * Make introductory video about Leo for PyCon2013China
By mid December.

Private email: http://mail.google.com/mail/u/0/#inbox/141ddfe09c389e4f
.. @+node:ekr.20131101080215.16488: *3* * Outreach to magazine editors
===== Steve Litt

I think the first step in getting this kind of review is to get more
fans who can write and who are listened to. To do that, you'd need to
give them enough of a burning desire to spend a few days learning the
ins and outs of Leo. I'll give you an idea how to do this later in this
email.

But first, I think Leo has an image problem. Mention Leo, and most
people say "it's an outliner." If that's all Leo was, VimOutliner would
have eaten Leo's lunch years ago --- VimOutliner's faster and has the
90% of outlining features that people use 90% of the time. Not only
that, face the facts, 95% of the population will never believe they
need an outliner or that an outliner would do them any good, or that
outlining is a skill they need to bother to acquire.

My understanding, and please correct me if I'm wrong, is that Leo is a
mechanism by which you can specify a computer program as an outline
like thing in an outliner like setting, flip a switch, and bang, there's
your program. THAT'S what's going to hook people.

So here's what to do. Make a 3 minute video showing how to compose an
application outline and turn it into a program. The program can be
trivially simple, but make the program as 2014 relevant as possible: A
web app would be nice. At the end of the video explain that although
this video's program was simple, Leo can be used to make arbitrarily
complex apps, and make them well.

Maybe have a second video showing how to make a GUI app. Maybe a 3rd
showing how to write a book in Leo, flip a switch, and have it be a
book, flip it back, and see your book as an outline again, ready for
changes, either minor, or structurally major.

Publicize these videos, and you're going to get some journalists
excited, and those are your reviews.

One more thing: Start publicizing different ways people use Leo.
Encourage them to write in with their unique uses, and publicize them.
I bet people are doing things with Leo you never dreamed of, and some
of those things might be the itch some journalist wants to scratch.
.. @+node:ekr.20131105020211.18059: *3* Per-node expansions!
https://groups.google.com/forum/#!topic/leo-editor/Wd0NtBLEZZk

The idea is store "ephemeral" or position-related data **in vnodes*. This
is a completely new idea in Leo's history!

Suppose every vnode contains a new ivar: v.expandedPositions, a list of
(copies of) positions at which v is to be expanded. This would work as
follows:

1. Contracting a node at position p clears p.v.expandedPositions. The happy
   side effects is that contracting any clone will contract them all.

2. Expanding a node at position appends p.copy() to p.v.expandedPositions,
   and purges any no-longer-existing positions from that list.

3. Leo's drawing code will call c.shouldBeExpanded(p) (instead of
p.isExpanded()) to determine whether to expand the outline node at position
p.

As always, changing outline structure will invalidate positions. Because
c.p and all it's ancestors are always expanded, the worst that can happen
when an outline changes is that some positions that *aren't* the present
position will contract unexpectedly. Most such contraction will occur off
screen.

Note: We could add v ivars for other kinds of data, such as marks, but
that's not going to happen. I think this trick is appropriate only in very
special circumstances. Furthermore, vnodes should be as small as possible.
.. @+node:ekr.20131017174814.17480: *3* c.shouldBeExpanded
@language python

def shouldBeExpanded(self,p):
    c,root,v = self,self.rootPosition(),p.v
    if p == c.p or p.isAncestorOf(c.p):
        return True
    if v.isExpanded():
        v.expandedList = [p2 for p2 in v.expandedList if c.positionExists(p2,root=root)]
        for p2 in v.expandedList:
            if p == p2:
                return True
    return False
.. @+node:ekr.20131030082936.17512: *3* Can't fix (yet) bug 1090950: refresh from disk - cut node ressurection
https://bugs.launchpad.net/leo-editor/+bug/1090950

A shock: fixing bug 1090950 re resurrected nodes may define Leo 5.0
https://groups.google.com/forum/#!topic/leo-editor/nIl3ud7Tbig


.. @+node:ekr.20130926053913.11569: *3* leoRope.py
.. @+node:ekr.20100828074347.5827: *3* Better support for vim
@language rest

About vim and Leo: no further major work is coming.
http://groups.google.com/group/leo-editor/browse_thread/thread/6882f02321dc1edf

Vim mode users: your top 3 complaints, please
http://groups.google.com/group/leo-editor/browse_thread/thread/141690c553bfde55
.. @+node:ekr.20100113075303.6270: *4* Vim problems
# None of these is easily solvable in Leo's present environment.
.. @+node:ekr.20100112051224.6239: *5* Displaying mode help
The "--> mode-help" command has the following issues related to the
display of the "Help" tab:

1. Key label always capitalized.

Vim commands are mapped to both lower-case and upper-case keys but always appear
mapped to upper-case keys within the "Help" tab.

2. Layout of tab's contents.

To improve readability and better support narrow tab cards, display the mode's
label without the "enter-" and "-mode" text and place the key label before the
mode label.

For example, the following entries would change from::
    enter-vi-delete-line-mode d
    enter-vi-delete-to-begin-of-word-mode b
to::
    d : vi-delete-line
    b : vi-delete-to-begin-of-word
.. @+node:ekr.20100112051224.6225: *5* Repeat last cursor movement command
Support the ';' key: repeat the last "To character" or "Find character" command.
.. @+node:ekr.20100113075303.6271: *5* Need mode-oriented bindings
Mapping a number to a command or an @mode node works but can not be used as it
prevents the number from being entered as text while in Vi's insert state.

Binding 'bksp' key to back-char to move back a character in command mode
prevents 'bksp' from deleting characters in text edit mode.
.. @+node:ekr.20080616110054.2: *5* Support vim dot command
The ability to repeat the last editing related command by pressing the period
key is not supported and there is no workaround in place.

Binding keys within nodes:

Some commands can be "easily" repeated by having the command's mode
bind itself to the period key.  This is not currently working.  

Support commands requesting input:

Add companion commands that reuse input.  For example, a zap-to-
character-again command could exist which will reuse the key entered
in the last zap-to-character command.  With this support, the mode
that performs the initial command would assign the period key to a
companion mode that is identical to the initial mode but with the zap-
to-character command replaced by the zap-to-character-again command.

Commands requiring companion commands are:
  zap-to-character
  find-character
  backward-find-character
  (Any others?)

Notes:

- The copy of the character should be saved somewhere that does NOT affect the
  contents of the clipboard.

- The same or a separate storage location can be used for all commands to retain
  a copy of the character entered by the user. It doesn't matter since only the
  last command is assigned to the period key to be re-executed.
.. @+node:ekr.20100112051224.6238: *5* Some commands do not work in headline
Leo functions exist which unconditionally set focus to the body pane
regardless of the active pane.

For example, bracket matching commands ("%" key) do not work within
a node's headline text.  Instead, the command is performed on the
node's body text.

Using the "undo" command (key 'u') to undo a change to a node's headline text
only works correctly after another node has been selected. It appears that
changes made to a node's headline text are not recorded in Leo's change history
until the edited node has lost focus.
.. @+node:ekr.20100112051224.6222: *5* Commands requesting user input
Commands requesting user input must be the last command executed within an @mode
node. This prevents the implementation of commands such as "yank to <character>"
that requires a "copy to clipboard" operation after the "find-character"
command.

======

Maybe we just need more commands...
.. @+node:ekr.20100112051224.6223: *5* Editing node headlines using @mode nodes
Commands modifying or selecting headline text do not work correctly within a
@mode node.

This eliminates accurate implementation of vi's delete/change/substitute/yank
object commands. As a workaround, the commands are currently written to only
select the text. The user must perform the subsequent delete, change,
substitute, and yank.
.. @+node:ekr.20100112051224.6246: *5* Missing commands/features
.. @+node:ekr.20100112051224.6234: *6* Move current line (to screen position)
Vi has a collection of "z<movement>" commands that will move the
current line to the top, middle, and bottom of the screen.  They are
not supported in Leo.
.. @+node:ekr.20100112051224.6235: *6* Move body text up/down
Vi maps keys to scroll the text up/down one line and by half the
number of visible lines.  Leo does not support this.

.. @+node:ekr.20110529115328.18247: *6* Block cursor
Having worked with Tk text canvases more that Qt, there still seem to
be things that it had that have to be worked around as the Qt people
just haven't seen the need for.

One is the block cursor, I giving Leo Vim like functionality, it would
be nice if one where supported, theses new kids just don't understand
something so primitive I guess.
.. @+node:ekr.20110202094848.12568: *6* Named marks
Another is named marks, in Vim you can store a number of cursor
locations, and recall them to jump around in your code.  This was also
useful in filling out templates as each stop could be given a name
mark.  This helped make filling out a template easier as you weren't
stuck in a linear filling in the blanks in a set order, template stops
where linked in rings, you could jump from the last stop back to the
first and make and changes you wanted on a second go round.  Gravity
of marks made things easier to inspect to determine what stops where
used and which ones were being bypassed.

As these things had an actual presence in the text buffer, it going to
be a little harder to come up with a reasonable work around.
.. @+node:ekr.20110115062009.6025: *5* Commands that work differently in Vim
.. @+node:ekr.20100112051224.6236: *6* Two kinds of words
Vi supports two types of words in its commands:

1. Words that consist of only a subset of the character set and
2. words that consist of all characters except the space and tab characters.

Leo's always considers a word to consist of a subset of characters
although some word related commands include different characters
than others.
.. @+node:ekr.20090629183608.8446: *6* Copy/paste/yank/delete
Yank vs. Yank:
Vi's "yank" commands copy the selected text TO the clipboard.
Leo's "yank" commands insert text FROM the clipboard.

copy-text in modes:
Leo's copy-text command does not work within a mode.  As a result,
all "copy to clipboard" capability is being implemented using the
kill-<object> command followed by Leo's "yank" command to put the
text back.

paste-text in modes:
The paste-text command does not work within an @mode node.  Leo's
"yank" command is used instead.

delete-node does not copy node to clipboard:
A copy-node command is issued to copy the node to the clipboard
followed by the delete-node command.
.. @+node:ekr.20100521090440.5887: *4* Generalize minibuffer code
@nocolor-node

From Tom L

This is hardwired for the first parameter.  Things I need to expand
this:

1. put in a variable that cycles through the tabStops

2. In this mock up, you are entering the parameters in the minibuffer,
a more advanced version would collect each keypress and put it in the
body at the current tabStop, a tab would finalize the entry and
advance to the next stop, no text other than the 'help', ends up in
the minibuffer.

Sinc I'm only modifying existing code without real understanding of
what Leo is doing, any guidance would be appreciated.

Tom
.. @+node:ekr.20110529115328.18254: *5* EKR notes
@language rest

The general idea is to make it easier to prompt for series of values.

This might be important in the vim project, but it is not worth doing outside the vim project.
.. @+node:ekr.20110529115328.18253: *5* code
@language python

#Just playing with part of a template system, the (partial) mock up for "range()" is:

def tabStopNaming (event=None):

  stateName = 'naming'
  k = c.k
  state = k.getState(stateName)

  help = ('start-value -- optional, -> fill-in or tab eliminate.  ',
           'end-value -- required, -> fill-in.  ',
           'step -- optional, ->fill-in or tab to eliminate.  ')
  tabStop = ('start-value', 'end-value', 'step')

  if state == 0:
      k.setLabelBlue(help[0],protect=True)
      k.getArg(event,stateName,1,tabStopNaming)
      # g.es('does this ever executed?') # yes, imediately!
  else:
      k.clearState()
      g.es_print('%s : %s' % (tabStop[0], k.arg))
      k.setLabelBlue('')

tabStopNaming()
.. @+node:ekr.20100112051224.6226: *4* Vim-related: Range prefix to commands/objects (k.getArgs)
The ability to specify a numeric range prefix is not supported. For example,
entering "3dd" will not delete the next three lines and "20G" will not move the
cursor to the 20th line in the file.

The ability to specify a numeric range prefix to an object is not supported. For
example, the "d2fx" command should Delete up to and including the 2nd Found "x"
character.
.. @+node:ekr.20131102044158.16568: ** For 4.11.1
.. @+node:ekr.20131101080215.16490: *3* * Fix option-key bug on Mac
@language rest

EKR: rev 6107: changes re Alt-Ctrl (Alt-Gr) keys.
leoEditCommands.py: changed selfInsertCommand. Added isPlain logic.

https://groups.google.com/forum/#!searchin/leo-editor/key$20handling$20broken/leo-editor/OBIMAFHigZo/R8zSbAD7eWoJ

I am trying Leo on OSX with Finnish keyboard layout.

To get the @ character, you have to press Option + 2. Option doubles as
"alt", so I guess it's misinterpreted as alt-2.

I recall there were email threads about alt gr, leo and international
keyboards, but I thought there was a resolution for that problem back then
(until I actually tried Leo on mac, that is).

Apart from this glitch, getting Leo running on Mac is much easier than I
remembered (just use homebrew to install PyQt).

@language python
.. @+node:ekr.20051125080855: *4* selfInsertCommand, helpers
def selfInsertCommand(self,event,action='insert'):

    '''Insert a character in the body pane.
    This is the default binding for all keys in the body pane.'''

    trace = False and not g.unitTesting
    c,k = self.c,self.k
    verbose = True
    w = self.editWidget(event)
    if not w: return # (for Tk) 'break'
    << set local vars >>
    assert g.isStrokeOrNone(stroke)

    if trace: g.trace('ch',repr(ch),'stroke',stroke)
    if g.doHook("bodykey1",c=c,p=p,v=p,ch=ch,oldSel=oldSel,undoType=undoType):
        return # (for Tk) "break" # The hook claims to have handled the event.
    if ch == '\t':
        self.updateTab(p,w)
    elif ch == '\b':
        # This is correct: we only come here if there no bindngs for this key. 
        self.backwardDeleteCharacter(event)
    elif ch in ('\r','\n'):
        ch = '\n'
        self.insertNewlineHelper(w,oldSel,undoType)
    elif inBrackets and self.autocompleteBrackets:
        self.updateAutomatchBracket(p,w,ch,oldSel)
    elif ch: # Null chars must not delete the selection.
        isPlain = stroke.find('Alt') == -1 and stroke.find('Ctrl') == -1
        i,j = oldSel
        if i > j: i,j = j,i
        # Use raw insert/delete to retain the coloring.
        if i != j:                  w.delete(i,j)
        elif action == 'overwrite': w.delete(i)
        if isPlain: # 2013/10/07: call insertKeyEvent for non-plain characters.
            w.insert(i,ch)
            w.setInsertPoint(i+1)
        else:
            g.app.gui.insertKeyEvent(event,i)
        if inBrackets and self.flashMatchingBrackets:
            self.flashMatchingBracketsHelper(w,i,ch)               
    else:
        return # (for Tk) 'break' # This method *always* returns 'break'

    # Set the column for up and down keys.
    spot = w.getInsertPoint()
    c.editCommands.setMoveCol(w,spot)

    # Update the text and handle undo.
    newText = w.getAllText()
    changed = newText != oldText
    if trace and verbose:
        g.trace('ch',repr(ch),'changed',changed,'newText',repr(newText[-10:]))
    if changed:
        # g.trace('ins',w.getInsertPoint())
        c.frame.body.onBodyChanged(undoType=undoType,
            oldSel=oldSel,oldText=oldText,oldYview=None)

    g.doHook("bodykey2",c=c,p=p,v=p,ch=ch,oldSel=oldSel,undoType=undoType)
    return # (for Tk) 'break'
.. @+node:ekr.20061103114242: *5* << set local vars >>
p = c.p

stroke = event and event.stroke or None
ch = event and event.char or ''

if ch == 'Return':
    ch = '\n' # This fixes the MacOS return bug.
if ch == 'Tab':
    ch = '\t'

name = c.widget_name(w)
oldSel =  name.startswith('body') and w.getSelectionRange() or (None,None)
oldText = name.startswith('body') and p.b or ''
undoType = 'Typing'
brackets = self.openBracketsList + self.closeBracketsList
inBrackets = ch and g.toUnicode(ch) in brackets
# if trace: g.trace(name,repr(ch),ch and ch in brackets)
.. @+node:ekr.20090213065933.14: *5* doPlainTab
def doPlainTab(self,s,i,tab_width,w):

    '''Insert spaces equivalent to one tab.'''

    start,end = g.getLine(s,i)
    s2 = s[start:i]
    width = g.computeWidth(s2,tab_width)

    if tab_width > 0:
        w.insert(i,'\t')
        ins = i+1
    else:
        n = abs(tab_width) - (width % abs(tab_width))
        w.insert(i,' ' * n)
        ins = i+n

    w.setSelectionRange(ins,ins,insert=ins)
.. @+node:ekr.20060627091557: *5* flashCharacter (leoEditCommands)
def flashCharacter(self,w,i):

    bg      = self.bracketsFlashBg or 'DodgerBlue1'
    fg      = self.bracketsFlashFg or 'white'
    flashes = self.bracketsFlashCount or 3
    delay   = self.bracketsFlashDelay or 75

    w.flashCharacter(i,bg,fg,flashes,delay)
.. @+node:ekr.20060627083506: *5* flashMatchingBracketsHelper
def flashMatchingBracketsHelper (self,w,i,ch):

    d = {}
    if ch in self.openBracketsList:
        for z in range(len(self.openBracketsList)):
            d [self.openBracketsList[z]] = self.closeBracketsList[z]
        reverse = False # Search forward
    else:
        for z in range(len(self.openBracketsList)):
            d [self.closeBracketsList[z]] = self.openBracketsList[z]
        reverse = True # Search backward

    delim2 = d.get(ch)

    s = w.getAllText()
    j = g.skip_matching_python_delims(s,i,ch,delim2,reverse=reverse)
    if j != -1:
        self.flashCharacter(w,j)
.. @+node:ekr.20060804095512: *5* initBracketMatcher
def initBracketMatcher (self,c):

    if len(self.openBracketsList) != len(self.closeBracketsList):

        g.es_print('bad open/close_flash_brackets setting: using defaults')
        self.openBracketsList  = '([{'
        self.closeBracketsList = ')]}'

    # g.trace('self.openBrackets',openBrackets)
    # g.trace('self.closeBrackets',closeBrackets)
.. @+node:ekr.20051026171121: *5* insertNewlineHelper
def insertNewlineHelper (self,w,oldSel,undoType):

    trace = False and not g.unitTesting
    c = self.c ; p = c.p
    i,j = oldSel ; ch = '\n'
    if trace:
        s = w.widget.toPlainText()
        g.trace(i,j,len(s),w)

    if i != j:
        # No auto-indent if there is selected text.
        w.delete(i,j)
        w.insert(i,ch)
        w.setInsertPoint(i+1)
    else:
        w.insert(i,ch)
        w.setInsertPoint(i+1)

        if (c.autoindent_in_nocolor or 
            (c.frame.body.colorizer.useSyntaxColoring(p) and
            undoType != "Change")
        ):
            # No auto-indent if in @nocolor mode or after a Change command.
            self.updateAutoIndent(p,w)

    w.seeInsertPoint()
.. @+node:ekr.20051026171121.1: *5* updateAutoIndent (leoEditCommands)
def updateAutoIndent (self,p,w):

    trace = False and not g.unitTesting
    c = self.c
    d = c.scanAllDirectives(p)
    tab_width = d.get("tabwidth",c.tab_width)
    # Get the previous line.
    s = w.getAllText()
    ins = w.getInsertPoint()
    i = g.skip_to_start_of_line(s,ins)
    i,j = g.getLine(s,i-1)
    s = s[i:j-1]

    # Add the leading whitespace to the present line.
    junk, width = g.skip_leading_ws_with_indent(s,0,tab_width)
    # g.trace('width',width,'tab_width',tab_width)

    if s and s [-1] == ':':
        # For Python: increase auto-indent after colons.
        if g.findLanguageDirectives(c,p) == 'python':
            width += abs(tab_width)

    if self.smartAutoIndent:
        # Determine if prev line has unclosed parens/brackets/braces
        bracketWidths = [width] ; tabex = 0
        for i in range(0,len(s)):
            if s [i] == '\t':
                tabex += tab_width-1
            if s [i] in '([{':
                bracketWidths.append(i+tabex+1)
            elif s [i] in '}])' and len(bracketWidths) > 1:
                bracketWidths.pop()
        width = bracketWidths.pop()

    ws = g.computeLeadingWhitespace(width,tab_width)
    if ws:
        if trace: g.trace('width: %s, tab_width: %s, ws: %s' % (
            width,tab_width,repr(ws)))
        i = w.getInsertPoint()
        w.insert(i,ws)
        w.setInsertPoint(i+len(ws))
        w.seeInsertPoint()
            # 2011/10/02: Fix cursor-movement bug.
.. @+node:ekr.20051027172949: *5* updateAutomatchBracket
def updateAutomatchBracket (self,p,w,ch,oldSel):

    # assert ch in ('(',')','[',']','{','}')

    c = self.c ; d = c.scanAllDirectives(p)
    i,j = oldSel
    language = d.get('language')
    s = w.getAllText()

    if ch in ('(','[','{',):
        automatch = language not in ('plain',)
        if automatch:
            ch = ch + {'(':')','[':']','{':'}'}.get(ch)
        if i != j: w.delete(i,j)
        w.insert(i,ch)
        if automatch:
            ins = w.getInsertPoint()
            w.setInsertPoint(ins-1)
    else:
        ins = w.getInsertPoint()
        ch2 = ins<len(s) and s[ins] or ''
        if ch2 in (')',']','}'):
            ins = w.getInsertPoint()
            w.setInsertPoint(ins+1)
        else:
            if i != j: w.delete(i,j)
            w.insert(i,ch)
            w.setInsertPoint(i+1)
.. @+node:ekr.20051026092433: *5* updateTab
def updateTab (self,p,w,smartTab=True):

    trace = False and not g.unitTesting
    c = self.c

    # g.trace('tab_width',tab_width)
    i,j = w.getSelectionRange()
        # Returns insert point if no selection, with i <= j.

    if i != j:
        # w.delete(i,j)
        c.indentBody()
    else:
        d = c.scanAllDirectives(p)
        tab_width = d.get("tabwidth",c.tab_width)
        if trace: g.trace(tab_width)

        # Get the preceeding characters.
        s = w.getAllText()
        start,end = g.getLine(s,i)
        after = s[i:end]
        if after.endswith('\n'): after = after[:-1]

        # Only do smart tab at the start of a blank line.
        doSmartTab = (smartTab and c.smart_tab and i == start)
            # Truly at the start of the line.
            # and not after # Nothing *at all* after the cursor.

        if trace:
            g.trace('smartTab',doSmartTab,'tab_width',tab_width)
                # 'i %s start %s after %s' % (i,start,repr(after)))

        if doSmartTab:
            self.updateAutoIndent(p,w)
            # Add a tab if otherwise nothing would happen.
            if s == w.getAllText():
                self.doPlainTab(s,i,tab_width,w)
        else:
            self.doPlainTab(s,i,tab_width,w)
.. @+node:ekr.20131104103309.16513: *3* Add key bindings to status line
.. @+node:ekr.20131102044158.16569: *3* fix find bugs
.. @+node:ekr.20131027064821.18715: *3* Autocompleter ? usually doesn't work
https://groups.google.com/forum/#!topic/leo-editor/rTN1S9u74RQ

 ​It works for me, but only in special cases.

The reason the *exact* example above works is that:

a) c.atFileCommands.write is *already* a valid completion and
b) c.atFileCommands.write is *also* a prefix of other at.FileCommands methods.

In that case, ​
 
​auto_completer_state_handler is still active, and the '?' characters works.

Obviously, there are many other situations where you have typed a unique method name, which causes auto_completer_state_handler to exit.  In those more common cases, the '?' character won't work.

There is no quick fix for this.  Probably a new command is needed.
.. @+node:ekr.20131004191204.16078: *3* cycle-all-focus doesn't work
# Use table?
.. @+node:ekr.20131103054650.16527: *3* fill-region & format-body can hang
.. @+node:ekr.20131025044901.17146: *3* Clone-to-last-node
# Don't change selected node!
.. @+node:ekr.20130803125244.17100: ** Docs & marketing
.. @+node:ekr.20131029095615.17089: *3* A cool tricks section
.. @+node:ekr.20130909111702.13058: *3* Allow paypal donations to Leo
.. @+node:ekr.20130806072439.20414: *3* Cannot open Leo files by double-click in Windows Explorer?
From: Nick_H <nah@plextek.co.uk>

Sorry, this is probably a foolish question, but when I double-click on
any Leo file on my desktop to launch Leo, it simply launches with the
default workbook.leo file open.
I can, of course, open any file via the File|Open dialog, but that's
not so convenient.
The file association contains the following command to execute for the
Open operation:
"C:\\Tools\\Python32\\python.exe" "C:\\Tools\\Leo-4.10-final\\launchLeo.py
%*"

Can you suggest what might be wrong?
Thank you!

Nick

.. @+node:ekr.20130806072439.20415: *4* Re: Cannot open Leo files by double-click in Windows Explorer?
From: "Edward K. Ream" <edreamleo@gmail.com>

"On Wed, Apr 18, 2012 at 12:20 AM, Matt Wilkie <maphew@gmail.com> wrote:

> the docs have the wrong version, It should match the above:
> http://webpages.charter.net/edreamleo/install.html#installing-leo-on-windows

Good catch.  I think rather than updating this for every release, I'll
try to generalize it a bit so people will understand what is intended.
 The fix will probably be tricky: it's so hard to be clear and general
at the same time.  Otoh, making instructions
Python-and-Leo-version-depenedent is pretty hopeless.
.. @+node:ekr.20130806072439.20416: *4* Re: Cannot open Leo files by double-click in Windows Explorer?
From: Matt Wilkie <maphew@gmail.com>

> The file association contains the following command to execute for the
> Open operation:
> "C:\\Tools\\Python32\\python.exe" "C:\\Tools\\Leo-4.10-final\\launchLeo.py
> %*"

it's the trailing %*, use "%1" instead.

You want %*  in a batch file. It passes all command line arguments to
the program being called.

"%1" passes just the file being clicked on, quoted for spaces etc.
When in a batch file %1 passes just the first command line parameter.

It is logical to expect %* to work for click file association as well,
but it doesn't. I don't know why.

.. @+node:ekr.20130806072439.20417: *4* Re: Cannot open Leo files by double-click in Windows Explorer?
From: Matt Wilkie <maphew@gmail.com>

> Set up file type association:
>
> C:\\> ftype LeoFile=3DC:\\Python27\\pythonw.exe C:\\apps\\leo\\launchLeo.py =E2=
=80=9C%1=E2=80=B3
> C:\\> assoc .leo=3DLeoFile=20
>
And put this leo.bat in %PATH%:
>
> @start /b "Leo" C:\\Python27\\python.exe C:\\apps\\leo\\launchLeo.py %*
>
Edward (or anyone else with access to bzr, I don't right now (and the last=
=20
time it didn't work anyway ;-): the docs have the wrong version, It should=
=20
match the above:
http://webpages.charter.net/edreamleo/install.html#installing-leo-on-window=
s

=20
-matt=20
.. @+node:ekr.20130806072439.20418: *4* Re: Cannot open Leo files by double-click in Windows Explorer?
From: Nick_H <nah@plextek.co.uk>

Many thanks to all for these replies!
This is my final "open" string in the Windows file associations:
"C:\\Tools\\Python32\\python.exe" "C:\\Tools\\Leo-4.10-final\\launchLeo.py"=20
--gui=3Dqttabs "%1"
Note that the brackets are needed round the %1 to cater for file paths=20
containing spaces.

Matt, thanks for the extra details about using ftype and assoc. I hadn't=20
realised those existed in Windows. For anyone else reading this, that is an=
=20
alternative to working through the file associations GUI.

Nick

On Saturday, April 14, 2012 4:30:10 PM UTC+1, Matt Wilkie wrote:
>
> > it's the trailing %*, use "%1" instead.
>
> Here is my setup...
>
> Set up file type association:
>
> C:\\> ftype LeoFile=3DC:\\Python27\\pythonw.exe C:\\apps\\leo\\launchLeo.py =E2=
=80=9C%1=E2=80=B3
> C:\\> assoc .leo=3DLeoFile
>
>
> And put this leo.bat in %PATH%:
>
> @start /b "Leo" C:\\Python27\\python.exe C:\\apps\\leo\\launchLeo.py %*
>
> --=20
> -matt
>
>
.. @+node:ekr.20130806072439.20419: *4* Re: Cannot open Leo files by double-click in Windows Explorer?
From: HansBKK <hansbkk@gmail.com>

On Tuesday, April 17, 2012 1:43:34 AM UTC+7, Matt Wilkie wrote:
>
> > there's a very cool tool called "PortableFileAssociator" that allows you 
> to
> > create a set of windows file associations, icons etc and enable/disable
>
> neat, thanks for the tip.
> oh, looks like it's problematic with portableapps.com suite 'cause of
> high false-positive AV warnings... but maybe the same functionality
> will be incorporated into the PA menu launcher. Cool.
> http://portableapps.com/node/15583?page=4
>

Yes, many cool tools like this use autohotkey, or a certain compiler that 
also gets used for some malware and triggers false positives for some of 
the sloppier a/v packages.

If you want to be safe, get a more balanced picture from one of these:
http://www.virustotal.com/
http://virusscan.jotti.org/en
.. @+node:ekr.20130806072439.20420: *4* Re: Cannot open Leo files by double-click in Windows Explorer?
From: Matt Wilkie <maphew@gmail.com>

> it's the trailing %*, use "%1" instead.

Here is my setup...

Set up file type association:

C:\\> ftype LeoFile=3DC:\\Python27\\pythonw.exe C:\\apps\\leo\\launchLeo.py =E2=
=80=9C%1=E2=80=B3
C:\\> assoc .leo=3DLeoFile


And put this leo.bat in %PATH%:

@start /b "Leo" C:\\Python27\\python.exe C:\\apps\\leo\\launchLeo.py %*
.. @+node:ekr.20130806072439.20421: *4* Re: Cannot open Leo files by double-click in Windows Explorer?
From: Matt Wilkie <maphew@gmail.com>

> there's a very cool tool called "PortableFileAssociator" that allows you to
> create a set of windows file associations, icons etc and enable/disable

neat, thanks for the tip.
oh, looks like it's problematic with portableapps.com suite 'cause of
high false-positive AV warnings... but maybe the same functionality
will be incorporated into the PA menu launcher. Cool.
http://portableapps.com/node/15583?page=4
.. @+node:ekr.20130806072439.20422: *4* Re: Cannot open Leo files by double-click in Windows Explorer?
From: HansBKK <hansbkk@gmail.com>

Here's my launch batch. Note nothing's actually installed

set HOME=E:\\aasync\\Data\\H_HOME
cd \\aasync\\PortableApps\\leo-editor
start "" "..\\CommonFiles\\Python27\\pythonw.exe" 
"..\\CommonFiles\\Python27\\Lib\\site-packages\\leo-editor4\\launchLeo.py" %*
exit
.. @+node:ekr.20130806072439.20424: *4* Re: Cannot open Leo files by double-click in Windows Explorer?
From: Eoin <eoinmccarthy@fastmail.fm>

I got the association working on Windows 7 using:

>ftype LeoFile=3D"C:\\Python322\\pythonw.exe" "C:\\Program Files (x86)\\Leo-4.9-final\\launchLeo.py" "%1"
>assoc .leo=3DLeoFile
>regsvr32 /i shell32.dll
.. @+node:ekr.20130806072439.20425: *4* Re: Cannot open Leo files by double-click in Windows Explorer?
From: "Edward K. Ream" <edreamleo@gmail.com>

On Fri, Apr 13, 2012 at 5:24 AM, Nick_H <nah@plextek.co.uk> wrote:

> "C:\\Tools\\Python32\\python.exe" "C:\\Tools\\Leo-4.10-final\\launchLeo.py
> %*"
>
> Can you suggest what might be wrong?

The last set of double quotes looks wrong.  Try:

"C:\\Tools\\Python32\\python.exe" "C:\\Tools\\Leo-4.10-final\\launchLeo.py" %*

In this case, none of the double quotes are needed, because the paths
have no embedded blanks, so this also should work:

C:\\Tools\\Python32\\python.exe C:\\Tools\\Leo-4.10-final\\launchLeo.py %*

Finally, unless you have a strong reason not to do so, I would suggest
adding the --gui=qttabs option::

C:\\Tools\\Python32\\python.exe C:\\Tools\\Leo-4.10-final\\launchLeo.py
--gui=qttabs %*
.. @+node:ekr.20130806072439.20426: *4* Re: Cannot open Leo files by double-click in Windows Explorer?
From: Matt Wilkie <maphew@gmail.com>

I'm glad you got it working.

>>regsvr32 /i shell32.dll

Just note that this command does a lot more than update file
associations, and may undo some other customizations you've done
(default program for camera preview, shortcut wizard behaviour, ...)
Here are some things it does:
http://www.pcworld.com/article/126116/windows_tips_fix_windows_glitches_by_reregistering_your_dlls.html

.. @+node:ekr.20130806072439.20427: *4* Re: Cannot open Leo files by double-click in Windows Explorer?
From: HansBKK <hansbkk@gmail.com>

This is a bit OT, but: for those like me who work in "portable" mode, 
there's a very cool tool called "PortableFileAssociator" that allows you to 
create a set of windows file associations, icons etc and enable/disable the 
whole profile at one time, without messing with the local system's registry.

Also handy for those not in portable mode, but working on different windows 
boxes and bored with having to tweak each one separately.
.. @+node:ekr.20130803125244.17101: *3* Gallery of screenshots
.. @+node:ekr.20130807203905.16650: *3* Leo in a nutshell (statistics)
https://groups.google.com/forum/#!topic/leo-editor/lgHE4OJSLzw

In a Nutshell, The Leo Editor...

- has had 15,508 commits made by 47 contributors
  representing 1,064,650 lines of code
- is mostly written in Python
  with an average number of source code comments
- has a well established, mature codebase
  maintained by a large development team
  with decreasing Y-O-Y commits
- took an estimated 292 years of effort (COCOMO model)
  starting with its first commit in February, 2002
  ending with its most recent commit 2 days ago 
.. @+node:ekr.20130806072439.20514: *3* Newbie Leo questions for php projects
From: Richard <richardjohnlyon@gmail.com>

I am looking into using Leo for a few php projects at work.
I think I have figured out how to use Leo, but was wondering if someone 
could have a look at my small test project and let me know if I am using it 
correctly. (The workbook should be attached, please let me know if there 
are any problems).

I like the idea of Leo, however I get the impression that if I use it 
'wrong' then it will be more of a hindrance than a help.

-----

Just realised that that attachment is useless.

What I have is :
Nodes:
@file foo.php
@file test.php
----- << includes >>
----- << Connect to the database >>
----- << Disconnect from the database >>
----- << Test echo >>
----- << External file class test >>

@file foo:
<?php
    class Foo
    {
        public $foo;
        public $bar;
        
        public function foobar()
        {
            echo $foo . $bar;
        }
    }
?>

@file test.php
<?php
    << includes >>
    << Connect to the database >>
    << Test echo >>
    << Disconnect from the database >>
    << External file class test >>
?>

<<includes>>:
require('foo.php');

<< Connect to the database >>
echo "Connecting to the database";

<< Test echo >>:
echo "This is a test";

<< Disconnect from the database >>:
echo "Disconnecting from the database";

<< External file class test >>:
$foo = new Foo();

$foo->foo = "foo";
$foo->bar = "bar";

$foo->foobar();

Does this seem right? Or should I be doing something differently?
.. @+node:ekr.20130806211959.17359: *3* User comments
.. @+node:ekr.20130807090137.11464: *4* From Vili
From: vili <viljem.tisnikar@gmail.com>

Despite I am no programmer, I have been using Leo for some years now
as my "Intelligent PIM" - I organize my (complex) life with Leo.

Many thanks to Edward and others for the great application.
.. @+node:ekr.20130806211959.17360: *4* Blog post about how Leo can improve organization of code bases
From: Rickard Lindberg <ricli85@gmail.com>

I wrote a blog post about how Leo can be used to improve the organization 
of our code bases.

If you are interested, you can read it over here: 
http://reflectionsonprogramming.com/2013/02/related-things-are-not-kept-together/

===== From: Randy Kramer <rhkramer@gmail.com>

Very interesting--I'm happy to see someone thinking about how to make 
understanding code bases easier.  (I'm a rather old wannabee programmer, so 
I'm not sure it will ever be of much use to me, nor that I can offer cogent 
comments.)

Are you familiar with the concept of literate programming as espoused by
Donald Knuth and others?

===== Rickard

Yes. I've read about literate programming and also tried it. I found that it
didn't work so well for me for the following reasons (At least that's what I
remember. It was many years since I tried.):

* Focus on text first instead of code made it harder for me to produce
  working code. I sometimes learn how to do something by trying it out and
  then refactor the solution.

* Unless you read the PDF (or whatever the final output is) you loose the
  structure. At least I did. It was just one big file with all kinds of
  things mixed together. An outline structure solves this problem.

===== Randy

If so, did that influence you at all, and, if so how? (Not that I think
literate programming is the way forward, although I like the concept and
have experimented with it--I once wrote a rather large Visual Basic (I
know, what can I say, I was stuck in the Microsoft world at the time)
program using a literate programming approach. I got it working to a
degree, but eventually had to devote more time to other things so never got
it fully up to spec.

===== Rickard

It influenced me mostly in that I started to think about how to best
present programs so that humans can understand them. I'm not sure literate
programming like Knuth uses it is the best way (in particular, I think the
programs are harder to modify), but I also think that a folder with just
source code is not so good either.
.. @+node:ekr.20130806211959.17363: *5* Re: Blog post about how Leo can improve organization of code bases
From: Matt Wilkie <maphew@gmail.com>

Nice article Rickard, I think it captures the background problem well.

I'm not sure the images communicate clones effectively -- but don't really
have an alternative suggestion that would be an improvement. It's just
really hard to appreciate how well they work without experiencing them!
.. @+node:ekr.20130806211959.17364: *5* Re: Blog post about how Leo can improve organization of code bases
From: Terry Brown <terry_n_brown@yahoo.com>

On Sun, 24 Feb 2013 03:12:16 -0800 (PST)
Rickard Lindberg <ricli85@gmail.com> wrote:

> I wrote a blog post about how Leo can be used to improve the organization 
> of our code bases.
> 
> If you are interested, you can read it over here: 
> http://reflectionsonprogramming.com/2013/02/related-things-are-not-kept-together/

Interesting - the python web application framework Django is really
tough in that regard, you might simultaneously want to work on python,
html template, css, java-script, url-dispatch, tests, model definitions.
In fact I've just made some updates to the bookmarks display plugin
which make using it effectively smoother, for a mouse user, anyway, to
help with this.  Will push them soon.
.. @+node:ekr.20130806211959.17365: *4* Leo as PIM and authoring tool
Josef <joe_da@gmx.net>
7/30/12
		
Recently I evaluated docear - a mind-mapping tool for collecting reference
data (written in Java). It automatically extracts bookmarks and annotations
from PDF files, and more, but it's support for authoring is still not up to
the task. I think it would be great if Leo could do some of the tasks
docear is doing.

Leo is primarily a literate programming editor, but also quite good at
organizing bits of information. Dragging a PDF into Leo currently just
creates an url to the PDF. This could be expanded to also extract data
(bookmarks, notes) from the PDF and to sync this data between Leo and the
PDF. This info could be placed in child nodes: bookmarks and notes could
even jump directly to the page in the PDF (although each PDF viewer seems
to have a different syntax for doing that). This would be a great way to
organize data sheets and specifications stemming from external sources.

Combining the above with an improved LaTeX support, one would get a very
powerful research and authoring tool - in my opinion with a much more
convenient interface than docear.

Perhaps it is too much work to duplicate all the work docear is doing. An
alternative may be to sync data somehow between docear and Leo. Docear
stores the data in a freeplane mind-map. Has anyone else thoughts about
this? Offray Vladimir Luna Cárdenas offray@riseup.net via googlegroups.com
	
7/30/12
		
I have been using Leo to write my thesis. I didn't know about Docear, but
my use was in some sense similar. I have a lot of @url links pointint to
the pdfs files and in a subtree I cut and paste the text of the pdf I want
to comment and made the comments inside the tree. These pdf were part of my
bibliographic entries and I'm now writing a .bib file for these, so I can
have in only one Leo tree all my thesis, with all the references to
external files and the annotations and bibtex entries for them. For me the
key point of Leo in academic writing is the tree view plus the clones and
ignore nodes. My thesis can have several layers, the external ones being
the actual writing and the deeper ones the references, texts, images, tools
that enable me to do that writing. Using clones and @rst-no-head directives
I can have the level of granularity of a paragraph, something that is not
possible on traditional word processor which are the writing tool of tools
like docear. This approach have some glitches:

* I still need to do some fine tunning to the LaTeX export for writing the
pdf as I want. I imagine that putting sphinx in the tool chain could change
that.

* I can not get much people of my companions using this advangages, besides
of myself, because of the difficult installation process of Leo in
Windows/Mac and the not so friendly interface for non-programmers. Other
light markup structured text writing programs like Nested[1] are more
easily used and understood despite of not having all the advantages and
flexibility of Leo.

So, in resume, may be the better approach is connecting Leo to Docear, so
you can have the advantages of both in terms of easy multiplataform
installation and friendly interface of the later and programmability,
flexibility and deeper organic structure of the former.

Offray

Terry Brown <terry_n_brown@yahoo.com>


> Recently I evaluated docear - a mind-mapping tool for collecting reference
> data (written in Java). It automatically extracts bookmarks and annotations
> from PDF files, and more, but it's support for authoring is still not up to
> the task. I think it would be great if Leo could do some of the tasks
> docear is doing.
>
> Leo is primarily a literate programming editor, but also quite good at
> organizing bits of information.

I would describe it as an general purpose outline that's very good at
editing code.

> Dragging a PDF into Leo currently just
> creates an url to the PDF. This could be expanded to also extract data
> (bookmarks, notes) from the PDF and to sync this data between Leo and the
> PDF. This info could be placed in child nodes: bookmarks and notes could
> even jump directly to the page in the PDF (although each PDF viewer seems
> to have a different syntax for doing that). This would be a great way to
> organize data sheets and specifications stemming from external sources.

I'm not really sure how notes get embedded in PDFs.  As an aside, there
is also capability for using Leo to manage bookmarks to web pages, with
notes, tags, and snippets.  Look at the mod_http plugin.  It uses a
javascript bookmark button in your browser to communicate with Leo.

> Combining the above with an improved LaTeX support, one would get a very
> powerful research and authoring tool - in my opinion with a much more
> convenient interface than docear.
>
> Perhaps it is too much work to duplicate all the work docear is doing. An
> alternative may be to sync data somehow between docear and Leo. Docear
> stores the data in a freeplane mind-map. Has anyone else thoughts about
> this?

Syncing between the two sounds a little cumbersome to me.  I wonder if
the PDF stuff could be integrated with some sort of BibTeX .bib file
management?

Do you really need the mindmap UI of docear?  I used to use Freemind
which has a very similar interface, but switched to Leo.  I like what
http://cmap.ihmc.us/ does, but it only does idea organization, no
authoring etc.  To me cmaptools is better at idea organizing than
mindmaps.

There is also the backlinks plugin for Leo, which allows arbitrary
networks of links instead of just the directed tree, and graphcanvas,
which allows graph layout of nodes.  There aren't comparable with the
mindmap layouts, but they head in that direction.  Also note Leo's
hidden UI flexibility in the context menus on the pane dividers, you
can open a new window for the graphcanvas plugin, which gives it much
needed screen real estate.

Cheers -Terry

Josef <joe_da@gmx.net>
7/30/12
		
no, I do not need the mindmap stuff at all. I had a look at short look at
cmaptools, and I agree the generalized graph approach seems better than a
standard mindmap. But I am quite happy with the tree view in Leo and as you
already mentioned, this can be extended with backlinks etc. I have used Leo
already to organize reference documents and write documentation (using
Latex).

What I do want is links to a particular page of a PDF - links to just a
file are not enough when you refer to documents with 100+ pages.
Unfortunately this seems to be difficult to achieve in a cross-platform
way, particular when trying to support different PDF viewers. Docear is
solving this (and other compatibility problems) by developing its own
integrated viewer (I do not suggest to do this for Leo).

On second thought, I don't think that extracting the bookmark and
annotation info is really important to me - I would keep that info in the
PDF, anyhow. I would write inside Leo addional notes, and the output text
(in Latex).

Some integration of Bibtex may be a good thing and needs to be thought out
- perhaps by using JabRef for this, or by recycling some pyBibliographer
code, but this is also low on my priority list.

Offray seems to have a very similar use case as I - although I do not write
a thesis, but specifications for scientific instruments. The point about
cross-platform installation ease is also well taken, so I will look into
some inter-operability here (either with docear or cmaptools). I see Leo
mainly as a personal project / information manager: the leo tree is not
easily shared with others, while the files Leo points to with @url, @auto,
@file etc can be shared quite easily. In this I use Leo as *my personal*
view on the project.

Ville Vainio <vivainio@gmail.com>
7/30/12
		
It seems that e.g. w/ foxit reader, you can open selected page from command
line (-n 123). Abstracting this for other pdf readers that support such a
thing should be no problem.
 
On Monday, July 30, 2012 8:08:23 PM UTC+2, Ville M. Vainio wrote:
     
    It seems that e.g. w/ foxit reader, you can open selected page from
    command line (-n 123). Abstracting this for other pdf readers that
    support such a thing should be no problem.
    
Yes, I suppose one could translate from a canonical representation inside
Leo to whatever the tool needs (using @setting). Ideally, one would even
have a choice between opening the new page in a different or in the same
PDF viewer instance as the last page, but few viewers support that (Okular
does - but I don't know any cross-platform solution).
.. @+node:ekr.20130806211959.17366: *4* persistent state with json as a leo abbreviation
From: Terry Brown <terry_n_brown@yahoo.com>

I've added an abbreviation to my myLeoSettings.leo abbreviations:
https://gist.github.com/tbnorth/5530059

It's the abbreviation "persist;;" and when you type that you get:

---cut here---
import json

json_state_file = "cache_info_file.json"
if not os.path.exists(json_state_file):
    json.dump({'cache_items':{}}, open(json_state_file, 'w'))
cache_info = json.load(open(json_state_file))

def main():

    # do stuff with cache_info...

if __name__ == '__main__':

    try:
        main()
    except:
        json.dump(cache_info, open(json_state_file, 'w'))
---cut here---

with appropriate interaction to customize all the parts which, in the
above example, include "cache_", i.e. the filename and the variable
name.

The point is it seems silly to create a module and hence a dependency
for what is barely 4 lines of actual code, but those 4 lines give you
very handy robust persistence, so something like an editor abbreviation
is the obvious way to make the available - nothing Leo specific here,
except that only serious editors have abbreviation like that ;-).
.. @+node:ekr.20130806211959.17369: *5* Re: persistent state with json as a leo abbreviation
From: Terry Brown <terry_n_brown@yahoo.com>


> How do you use the code inserted by the abbreviation? 

The corrected version is below for reference - I had `except` instead
of `finally` in the first version, so you data was only saved if
something went wrong :-)

It's just a framework for providing a dictionary the contents of which
persist between runs of the program.  I've used it for code that's
making lots of small url requests against a server, to cache the
results so that during development the crash / debug / re-run cycle is
faster because each piece of data is requested only once, ever, not once
every run.  More recently I was using it to store key value pairs of
filenames and a comment on the issue in the file, knowing that
completing the analysis of the issues in the files would take more than
one run of the program which was identifying the issues.

So in the example below, the content of the cache_info dictionary is
persistent, whatever main() does with it is seen next time the
program's run.  Nothing Leo specific except that it's really just an
import statement plus 5 lines of code and doesn't seem worth its own
file, but is more than you want to re-type all the time either, so
ideal for an abbreviation in your favorite editor.

I've added a couple of comments in the version below.

Cheers -Terry

---cut here---
import json

# name for persistent data store
json_state_file = "cache_info_file.json"   
if not os.path.exists(json_state_file):
    # create persistent data store if it doesn't exist
    json.dump({'cache_items':{}}, open(json_state_file, 'w'))
# load persistent data
cache_info = json.load(open(json_state_file))

def main():

    # do stuff with cache_info...

if __name__ == '__main__':

    try:
        main()
    finally:
        # save altered persistent data
        json.dump(cache_info, open(json_state_file, 'w'), indent=4)
---cut here---

.. @+node:ekr.20130806211959.17370: *4* why Leo
From: Terry Brown <terry_n_brown@yahoo.com>

Because I have two nodes which were originally identical but are now
different and I want to see the differences.

My outline loads a @file called ~/.leo/t/gen which contains a @button
with several @rclick children for commonly used tasks.  So I add a new
one, @rclick diff

  selected = c.getSelectedPositions()
  open('/tmp/a_diff', 'w').write(selected[0].b)
  open('/tmp/b_diff', 'w').write(selected[1].b)
  import os
  os.system("xxdiff /tmp/a_diff /tmp/b_diff &")

which is horrible for a number of reasons but also took only moments
to write.  And now, not only does this Leo session have a visual node
diff capability, but also every future session which loads ~/.leo/t/gen.

When you can go from wanting to having a feature in less time than it
takes to write an email about it - well, that's "why Leo".

(I also have @file ~/.leo/sql and @file ~/.leo/dml for commands for
handling SQL and an XML dialect I use a lot, it's a great way to manage
little snippet functions)
.. @+node:ekr.20130806211959.17371: *5* Fw: why Leo
From: Terry Brown <terry_n_brown@yahoo.com>

Because I have two nodes which were originally identical but are now
different and I want to see the differences.

My outline loads a @file called ~/.leo/t/gen which contains a @button
with several @rclick children for commonly used tasks.  So I add a new
one, @rclick diff

  selected = c.getSelectedPositions()
  open('/tmp/a_diff', 'w').write(selected[0].b)
  open('/tmp/b_diff', 'w').write(selected[1].b)
  import os
  os.system("xxdiff /tmp/a_diff /tmp/b_diff &")

which is horrible for a number of reasons but also took only moments
to write.  And now, not only does this Leo session have a visual node
diff capability, but also every future session which loads ~/.leo/t/gen.

When you can go from wanting to having a feature in less time than it
takes to write an email about it - well, that's "why Leo".

(I also have @file ~/.leo/sql and @file ~/.leo/dml for commands for
handling SQL and an XML dialect I use a lot, it's a great way to manage
little snippet functions)

Cheers -Terry
.. @+node:ekr.20130806211959.17374: *6* Re: why Leo
From: wgw <wgwinder@gmail.com>

Useful!

For fun (and perhaps of some use), here is a brute compare of trees. I use
meld, which has a great interface.

I think I will set up a pyflakes button as well; I haven't seen it as part
of Leo, though the Leo error python messages are good.

-----------------------

def add_text(nd):
    """recursively add to text"""
    text =3D "\\n\\n>> " + nd.h
    text +=3D "\\n\\n%s" % nd.b
    for child in nd.children():
        text +=3D add_text(child)
    return text

selected =3D c.getSelectedPositions()
open('/tmp/a_diff', 'w').write(add_text(selected[0]).encode("utf-8"))
open('/tmp/b_diff', 'w').write(add_text(selected[1]).encode("utf-8"))
import os
os.system("meld /tmp/a_diff /tmp/b_diff &")

-------------


Le vendredi 1 f=E9vrier 2013 11:08:30 UTC-8, Terry a =E9crit :
>
> Because I have two nodes which were originally identical but are now
> different and I want to see the differences.
>
> My outline loads a @file called ~/.leo/t/gen which contains a @button
> with several @rclick children for commonly used tasks.  So I add a new
> one, @rclick diff
>
>   selected =3D c.getSelectedPositions()
>   open('/tmp/a_diff', 'w').write(selected[0].b)
>   open('/tmp/b_diff', 'w').write(selected[1].b)
>   import os
>   os.system("xxdiff /tmp/a_diff /tmp/b_diff &")
>
> which is horrible for a number of reasons but also took only moments
> to write.  And now, not only does this Leo session have a visual node
> diff capability, but also every future session which loads ~/.leo/t/gen.

>
> When you can go from wanting to having a feature in less time than it
> takes to write an email about it - well, that's "why Leo".
>
> (I also have @file ~/.leo/sql and @file ~/.leo/dml for commands for
> handling SQL and an XML dialect I use a lot, it's a great way to manage=

> little snippet functions)
>
> Cheers -Terry
>

.. @+node:ekr.20130806211959.17375: *4* Fidel's first post
From: <fidelperez@gmail.com>

This is my first post on this group, as I discovered your software only 
yesterday, but I am already migrating all my data, weblinks, etc, to it. 
Love it.

I found it because I was planning on programming something similar (by far 
more primitive of course), but *luckily* I found it just while I was 
starting with my first steps. What I also mean by this is its a rather 
difficult software to find by non programer users who could also greatly 
benefit from it. Im so glad I found it.

The main reason for me wanting a tool which can track different types of 
information (images, videos, etc), is to make such a program able not only 
to track the information just in the way I like it, but to also operate 
with it avoiding repetitive tasks for me.

Thanks for your software, Im really excited to have found it.
.. @+node:ekr.20130806211959.17307: *3* Help (For FAQ?)
@language rest
.. @+node:ekr.20130807203905.16678: *4* For Implementors
@language rest

- Don't read code: use g.trace and g.pdb instead.
- Where the bodies are hidden.
    - self.w in leoEditCommands.py
- Complex code that *can't* be simplified.
- The top 20 methods.  You must understand these *in general*.
    - k.masterKeyHandler.
    - qt.eventFilter.
    
** Add mandatory _kind fields to all g.Bunches.
.. @+node:ekr.20130807203905.16679: *5* Centralizing focus handling (to make debugging easier)
From: "Ville M. Vainio" <vivainio@gmail.com>

I am having some problems wrapping my head around how focus behaves
throughout leo.

IMO it would be a good idea to have only one place in Leo where focus is
explicitly set. E.g. g.setFocus(widget). This implementetation would
suffice:

def setFocus(widget):
  widget.setFocus()

Reasoning: it would be handy to add debugging stuff here, to see why my
focus stuff is failing in alt-x go-anywhere handling.

(My guess is treeFocusHelper only understanding focus being either in tree
or body, but no time to explore further now)

===== EKR

In fact, there is only one such place: c.outerUpdate.  The various
xWantsFocus methods simply set ivars, which c.outerUpdate uses to set the
focus when a command completes.

The various xWantsFocusNow methods call c.outerUpdate immediately.  Usually
we don't want to do this, because it could cause screen flash, but
sometimes the immediate update is essential.

I've marked this thread as a topic for implementers.  Such things will form
the basis for documentation for my successors.
.. @+node:ekr.20130807203905.16681: *5* Free "continuous integration" for Leo
From: "Ville M. Vainio" <vivainio@gmail.com>

--089e0122f80868cb1b04dce55d84
Content-Type: text/plain; charset=ISO-8859-1

Someone may be interested in investigating a free CI system for Leo:

https://travis-ci.org/

This could e.g. create debian packages for daily builds, run unit tests,
check stuff with lint, try compiling with python3 so we (*cough*) wouldn't
have accidental print statements in the source...
.. @+node:ekr.20130807203905.16684: *5* Toolkit independent apis
From: "Ville M. Vainio" <vivainio@gmail.com>

Ramblings relevant to Leo, by the PyQt lead developer:

http://www.riverbankcomputing.co.uk/static/Docs/dip/architecture.html#the-realities-of-software-development

esp "The Myth of Toolkit Independence"

===== EKR

Leo's core benefits greatly from toolkit independence, despite some
(usually minor) extra complexity. Obviously, this has not constrained
what plugins can do.

This is pretty much a non-issue for Leo.  The reason is clear enough:
the hundreds of commands defined in Leo's core are mostly
straightforward renditions of emacs text commands.  There, the
constraints of an abstraction layer do not pinch.  Furthermore, using
common gui-level code is a good application of the DRY (Don't Repeat
Yourself) principle, as recent bug fixes in the common code
illustrate.

The code for ensuring that the outline and body text are updated
properly (and in synch!) is much more difficult, but the difficulties
are fundamental: they have almost nothing to do with actual guis.

In short, I think Leo's design uses the best of the gui-dependent and
gui-independent approaches.
.. @+node:ekr.20130806211959.17315: *4* Background Images in body pane?
From: tfer <tfetherston@aol.com>

I was wondering if the Qt widget used for body text has a provision for 
background images?

I'm thinking that it might be interesting to have some wallpapers/tiles to 
visually represent various categories of methods, e.g. initors, setters, 
getters, etc.  Maybe ones that hint at the uses of a particular design 
pattern.  Maybe us a uA to control setting?
.. @+node:ekr.20130806211959.17316: *5* Re: Background Images in body pane?
From: "Edward K. Ream" <edreamleo@gmail.com>

On Fri, Jul 13, 2012 at 3:57 PM, tfer <tfetherston@aol.com> wrote:

> I was wondering if the Qt widget used for body text has a provision for
> background images?
>

Sorry for the delay in responding.  Leo's body pane is a QTextBrowser:
http://qt-project.org/doc/qt-4.8/qtextbrowser.html
a subclass of QTextEdit.  QTextBrowser also inherits from QFrame and
QWidget, so there *might* be a way to have a background image "leak"
through the text.
.. @+node:ekr.20130806211959.17317: *5* Re: Background Images in body pane?
From: Terry Brown <terry_n_brown@yahoo.com>

--MP_/NJ5QIult88.7_K/HpvnV2eA

On Wed, 1 May 2013 04:19:52 -0500
"Edward K. Ream" <edreamleo@gmail.com> wrote:

> On Fri, Jul 13, 2012 at 3:57 PM, tfer <tfetherston@aol.com> wrote:
> 
> > I was wondering if the Qt widget used for body text has a provision for
> > background images?
> >
> 
> Sorry for the delay in responding.  Leo's body pane is a QTextBrowser:
> http://qt-project.org/doc/qt-4.8/qtextbrowser.html
> a subclass of QTextEdit.  QTextBrowser also inherits from QFrame and
> QWidget, so there *might* be a way to have a background image "leak"
> through the text.
> 
> Edward
> 

QTextEdit#richTextEdit { background-image: url('/home/tbrown/Desktop/cow2.jpg'); }

in the stylesheet gives the effect attached (i.e. it works).

If you wanted node specific backgrounds Leo would have to start setting
an attribute on the body widget, probably the gnx, so you could do

QTextEdit#richTextEdit[leo_gnx='tbrown.20130430222443.19340'] { 
  background-image: url('/home/tbrown/Desktop/cow2.jpg'); 
}

Cheers -Terry

.. @+node:ekr.20130806211959.17318: *5* Re: Background Images in body pane?
From: "Edward K. Ream" <edreamleo@gmail.com>

On Wed, May 1, 2013 at 8:42 AM, Terry Brown <terry_n_brown@yahoo.com> wrote:

>
>
> QTextEdit#richTextEdit { background-image:
> url('/home/tbrown/Desktop/cow2.jpg'); }
>
> in the stylesheet gives the effect attached (i.e. it works).
>
> If you wanted node specific backgrounds Leo would have to start setting
> an attribute on the body widget, probably the gnx, so you could do
>
> QTextEdit#richTextEdit[leo_gnx='tbrown.20130430222443.19340'] {
>   background-image: url('/home/tbrown/Desktop/cow2.jpg');
> }
>

Wow!  Thanks for this.  LeoUser wrote a version of Leo in Jython (using the
Swing classes), and he claimed that he could watch *movies* in the body
pane :-)

I'll add this to the Leo/To Document list.  Not sure yet how that list is
going to get translated into action.  Still reading Getting Things Done :-)
.. @+node:ekr.20130806211959.17319: *4* Best way to synchronize/update myLeoSettings.leo and leoSettings.leo ?
From: wgw <wgwinder@gmail.com>

For the moment, I use Meld to compare/update myLeoSettings.leo file. That 
seems a bit error-prone. Is there a better way? By update, I mean that, for 
example, in the bzr copy of LeoSettings.leo, the code_wise node says :

True: use codewise completions.
False: use leo-specific completions.

This setting is no longer used!

But in my (now old) myLeoSettings.leo file it says: 

True: use codewise completions.
False: use leo-specific completions

I want to transfer that updated setting comment to myLeoSettings so that I 
don't have to refer to LeoSetttings.leo when I tweak my installation. 

Another example: the plugins list will change with new plugins or 
eliminated plugins, but those changes won't be noted in the myLeoSettings 
file. So you have to check both settings files to find/enable plugins.

In general, it would seem useful to be able to merge the two leo files 
(like bzr merge?) or somehow make note of differences in the myLeoSettings 
file. 

This is starting to sound complicated.... :) Sorry!

EKR

It is complicated.  One tiny workaround is to delete nodes from
myLeoSettings.leo if and when they become unused.  More generally, you only
have to put nodes in myLeoSettings.leo if they are different from the
defaults.  But you probably already know that :-)

Really, this is a special case of the fundamental problem the Leo
developers have been struggling with:  Leo is great for storing gobs of
data, but not so great at sharing.  As a result, everyone, including Leo's
developers, struggles to remember, access or browse all the great stuff
that is already present.

Requiring tags is no solution: it's hopeless to require volunteers to do
anything :-)  I'm not just making a joke.  Someone who contributes a script
to this Google Group is under no further obligation to somehow be
compatible with *any* other submission rules.  Somehow, it's up to me, or
the other core developers, to find a simple, reliable way of "indexing" the
submissions.  Right now I have no solutions.
.. @+node:ekr.20130806211959.17320: *4* Create Pane For matplotlib chart
From: felix74 <hjuucy@googlemail.com>

I'm trying to create a interactive chart in a embedded in a new leo pane 
using matplotlib. However, I am not sure about the the best way  to 
implement this. I would appreciate some guidance on this please? The 
questions I would like answered are:
1/ How do I create a new blank pane for embedding a chart as well as other 
QtWidgets.
2/ Can I do this in a script or do I need to work with leo source 

The context for wanting to do this is that I want to create a data 
processing and visualization tool kit in leo. Like Excel but using nodes 
instead of columns. As such I have data in nodes and can create new data 
nodes by applying python functions to data in existing nodes. The thing 
missing is the visualization within a leo pane (I can easily launch a chart 
in it's own window) .
.. @+node:ekr.20130806211959.17321: *5* Re: Create Pane For matplotlib chart
From: Terry Brown <terry_n_brown@yahoo.com>

On Tue, 18 Sep 2012 05:59:59 -0700 (PDT)
felix74 <hjuucy@googlemail.com> wrote:

> Terry,
>  
> Thanks for your help with this it was very helpful and a lot simpler than I 
> feared. I have managed to get a matplotlib graph embedded within a pane in 
> leo as a widget. I now need some help with how to interact with the 
> widget using scripts in leo. I am unsure about the following:
>  
> *1/ How do I expose the widget within th leo python environment?* 

If you were only going to have one and you weren't going to destroy it,
you could just do something simple like c._matplot = self in its
constrictor (assuming c was passed to the constructor).

If you're going to have more than one and they may be destroyed, it
might be simplest to let the free_layout / nested_splitter system manage
them.

ts = c.free_layout.get_top_splitter()
matplotters = ts.findChildren(myMatplotWidget)

should return a list of the widgets of your class in the layout, but
only if they're in the main window, widgets in extra windows opened
from the "Open window" context menu item would be missed, I can add a
find_children() method to complement the find_child() method the
splitters already have to account for this.

Detail: the above is just using Qt's QObject.findChildren(), the
nested_splitter find_child() and (not yet written) find_children()
versions search the extra windows as well.

> Here I have created a self.mat in your MatplotPaneProvider class to make 
> the windget accessible but it doesn't feel like the correct way to do this. 

It should probably provide a fresh myMatplotWidget every time it's
called, so don't construct one in the Provider's init, but in the
ns_provide method.

> from PyQt4 import QtGui
> class MatplotPaneProvider:
> def __init__(self, c):
>      self.c = c
>     * self.mat = myMatplotWidget()*
>      if hasattr(c, 'free_layout'):
[snip]  
> *2/I would also like to make the widget accessible from any script within 
> leo. What's the leo way of doing this?*

See above.

> *3/ If I create more than 1 pane containing these widgest. How do I switch 
> between them in scripts?*

Above again :-)
 
> *4/ Running this script more than once creates multiple items for Add 
> Matplot when pressing the Action button. How do I stop this from happening? 
> I have alrewady tried returning a unique integer in * ns_provider_id *but 
> that did not work.*

The value returned by ns_provider_id should be unique for the provider
class, but constant.  So it can just return "matplotlib provider ver 1"
or something.
.. @+node:ekr.20130806211959.17323: *5* Re: Create Pane For matplotlib chart
From: felix74 <hjuucy@googlemail.com>




Terry,
 
Thanks for your help with this it was very helpful and a lot simpler than I 
feared. I have managed to get a matplotlib graph embedded within a pane in 
leo as a widget. I now need some help with how to interact with the 
widget using scripts in leo. I am unsure about the following:
 
*1/ How do I expose the widget within th leo python environment?* 
Here I have created a self.mat in your MatplotPaneProvider class to make 
the windget accessible but it doesn't feel like the correct way to do this. 
 
from PyQt4 import QtGui
class MatplotPaneProvider:
def __init__(self, c):
     self.c = c
    * self.mat = myMatplotWidget()*
     if hasattr(c, 'free_layout'):
         splitter = c.free_layout.get_top_splitter()
     if splitter:
         splitter.register_provider(self)
    def ns_provides(self):
         return[('Add matplot', '_add_matplot_pane')]
    def ns_provide(self, id_):
         if id_ == '_add_matplot_pane':
         c = self.c
         return self.mat
 
    def ns_provider_id(self):

# used by register_provider() to unregister previously registered
# providers of the same service
# provider ID is not the same as the service id_ above
return "completely unique value here"

 
*mat = MatplotPaneProvider(c)*
*mat.mat.someMethod()*
*mat.mat.someOtherMethod()*
 
*2/I would also like to make the widget accessible from any script within 
leo. What's the leo way of doing this?*
 
*3/ If I create more than 1 pane containing these widgest. How do I switch 
between them in scripts?*
** 
*4/ Running this script more than once creates multiple items for Add 
Matplot when pressing the Action button. How do I stop this from happening? 
I have alrewady tried returning a unique integer in * ns_provider_id *but 
that did not work.*
 
.. @+node:ekr.20130806211959.17324: *5* Re: Create Pane For matplotlib chart
From: Terry Brown <terry_n_brown@yahoo.com>

On Sun, 16 Sep 2012 22:23:18 -0700 (PDT)
felix74 <hjuucy@googlemail.com> wrote:

> I'm trying to create a interactive chart in a embedded in a new leo pane 
> using matplotlib. However, I am not sure about the the best way  to 
> implement this. I would appreciate some guidance on this please? The 
> questions I would like answered are:
> 1/ How do I create a new blank pane for embedding a chart as well as other 
> QtWidgets.
> 2/ Can I do this in a script or do I need to work with leo source 

You can run this script from any body pane:
---cut here---
from PyQt4 import QtGui
class MatplotPaneProvider:
    def __init__(self, c):
        self.c = c
        if hasattr(c, 'free_layout'):
            splitter = c.free_layout.get_top_splitter()
            if splitter:
                splitter.register_provider(self)
    def ns_provides(self):
        return[('Add matplot', '_add_matplot_pane')]
    def ns_provide(self, id_):
        if id_ == '_add_matplot_pane':
            c = self.c
            w = QtGui.QSlider()
            return w
    def ns_provider_id(self):
        # used by register_provider() to unregister previously registered
        # providers of the same service
        # provider ID is not the same as the service id_ above
        return "completely unique value here"

MatplotPaneProvider(c)
---cut here---

Paste just as above and run the script.  Nothing happens.  Right click
on one of the pane dividers and select Insert.  A new pane with a
button 'Action' appears.  Click it, and select "Add matplot" from the
context menu.

Instead of "w = QtGui.QSlider()", you want "w = myMatplotWidget()"
.. @+node:ekr.20130806211959.17325: *4* How to call functions from LeoPyRef.Leo
From: <fidelperez@gmail.com>

I am going through something similar Matt Wilkie went through in this
post<https://groups.google.com/forum/?fromgroups=#!searchin/leo-editor/leopyref/leo-editor/pWyd5ae952I/kvxf_H-QBq4J>
.

Basically I can find interesting functions in LeoPyRef.leo but I dont know 
how to access them from my new leo scripts.

I dont get the difference when I have to call them using g.Functionname(), 
c.functionname(), or when those wont do.

How can I call the function "insertIconFromFile"?
How can I know how to call functions found in LeoPyRef.leo?

Thanks!

Ps: When I get that, I will already have a bookmarks importer from 
chrome/mozilla which will also import the icons of the links! x)
I will prepare some more interesting utils (import mindmap, etc) then 
release them together with manuals oriented to noob users.

.. @+node:ekr.20130806211959.17326: *5* Re: How to call functions from LeoPyRef.Leo
From: <fidelperez@gmail.com>

Sounds great!
So, in the search results, will I be able to know how to call that function?
IE, if I find insertIconFromFile, will I be able to know that I can call it
through using c.editCommands.insertIconFromFile?


On Monday, May 20, 2013 3:47:35 PM UTC+2, Terry wrote:
>
> On Mon, 20 May 2013 04:00:59 -0700 (PDT)
> Fidel P=E9rez <fidel...@gmail.com <javascript:>> wrote:
>
> > Ok, in order to print icons, the code is this:
> >
> > c.editCommands.insertIconFromFile(path)
> >
> > Im quoting from this Leo manual<
> http://leoeditor.com/scripting.html#import-objects>,
> > "inserting and deleting icons" section -_-
> >
> > Although I still have a mess on which functions can be called how, and
> > where to find the list of classes that can be called such as
> "editCommands"
> > and the rest that they might exist.
>
> I'm not aware of a general solution to the problem of finding the
> various pieces of Leo's class structure.  Basically there are all these
> classes defined in the source, and instances of these are attached to
> each other in a hierarchical network (with loops).
>
> I've written an introspection function which lists the methods and
> instance variables (and class variables) of an arbitrary object by name
> and by type.  I should release it.  It builds its lists in a Leo
> outline, so you can navigate around that outline and expand nodes by
> introspection as needed.
>
> It occurs to me that the same code could be used to search Leo's
> runtime object hierarchy for you, i.e. you enter 'insertIconFromFile'
> and it recursively searches for it.
>
> Cheers -Terry
>

.. @+node:ekr.20130806211959.17327: *5* Re: How to call functions from LeoPyRef.Leo
From: "Edward K. Ream" <edreamleo@gmail.com>

On Mon, May 20, 2013 at 8:47 AM, Terry Brown <terry_n_brown@yahoo.com>wrote:

> On Mon, 20 May 2013 04:00:59 -0700 (PDT)
> Fidel P=C3=A9rez <fidelperez@gmail.com> wrote:
>

> Although I still have a mess on which functions can be called how, and
> where to find the list of classes that can be called such as
"editCommands"
> and the rest that they might exist.

I'm not aware of a general solution to the problem of finding the
> various pieces of Leo's class structure.  Basically there are all these
> classes defined in the source, and instances of these are attached to
> each other in a hierarchical network (with loops).
>

I suppose you could say that there is no general solution, but the
situation isn't really all that difficult.

Start with c.  We know what that is:  it is a commander object representing
an open outline.

There are **official ivars** of c, all referring to wrapper classes defined
in leoFrame.py:

c.frame: an instance of leoFrame.
c.frame.tree: an instance of  leoTree.
c.frame.body: an instance of leoBody.
c.frame.log: an instance of leoLog.

The tree, body and log objects have a *ctrl* objects, which are *wrapper*
classes:

c.frame.tree.treeCtrl
c.frame.body.bodyCtrl
c.frame.log.logCtrl

In particular, see
http://leoeditor.com/scripting.html#c-frame-body-bodyctrlfor a
description of the high-level text interface supported by all
high-level text widgets, including the log and body classes.

These wrapper classes have a widget ivar, which is a reference to the
corresponding Qt widget object.  For example::

    import PyQt4.QtGui as QtGui
    w =3D c.frame.body.bodyCtrl.widget
    g.es(w)
    g.es(isinstance(w,QtGui.QTextBrowser)

yields::

    (LeoQTextBrowser) 62418136
    True

As shown, the LeoQTextBrowser class is a real (subclass of) QTextBrowser.

HTH.  I've made a note to discuss official ivars in more detail in the
scripting chapter.
.. @+node:ekr.20130806211959.17328: *5* Re: How to call functions from LeoPyRef.Leo
From: <fidelperez@gmail.com>

Ok, in order to print icons, the code is this:

c.editCommands.insertIconFromFile(path)

Im quoting from this Leo manual<http://leoeditor.com/scripting.html#import-objects>,
"inserting and deleting icons" section -_-

Although I still have a mess on which functions can be called how, and
where to find the list of classes that can be called such as "editCommands"
and the rest that they might exist.
Thanks!

On Sunday, May 19, 2013 12:43:50 PM UTC+2, Fidel P=E9rez wrote:
>
> Hi, I am going through something similar Matt Wilkie went through in this
> post<https://groups.google.com/forum/?fromgroups=3D#!searchin/leo-editor/leopyref/leo-editor/pWyd5ae952I/kvxf_H-QBq4J>
> .
>
> Basically I can find interesting functions in LeoPyRef.leo but I dont know
> how to access them from my new leo scripts.
>
> I dont get the difference when I have to call them using g.Functionname(),
> c.functionname(), or when those wont do.
>
> How can I call the function "insertIconFromFile"?
> How can I know how to call functions found in LeoPyRef.leo?
>
> Thanks!
>
> Pd: When I get that, I will already have a bookmarks importer from
> chrome/mozilla which will also import the icons of the links! x)
> I will prepare some more interesting utils (import mindmap, etc) then
> release them together with manuals oriented to noob users.
>

.. @+node:ekr.20130806211959.17329: *5* Re: How to call functions from LeoPyRef.Leo
From: Terry Brown <terry_n_brown@yahoo.com>

On Mon, 20 May 2013 04:00:59 -0700 (PDT) <fidelperez@gmail.com> wrote:

> Ok, in order to print icons, the code is this:
>
> c.editCommands.insertIconFromFile(path)
>
> Im quoting from this Leo manual<http://leoeditor.com/scripting.html#import-objects>,
> "inserting and deleting icons" section -_-
>
> Although I still have a mess on which functions can be called how, and
> where to find the list of classes that can be called such as "editCommands"
> and the rest that they might exist.

I'm not aware of a general solution to the problem of finding the
various pieces of Leo's class structure.  Basically there are all these
classes defined in the source, and instances of these are attached to
each other in a hierarchical network (with loops).

I've written an introspection function which lists the methods and
instance variables (and class variables) of an arbitrary object by name
and by type.  I should release it.  It builds its lists in a Leo
outline, so you can navigate around that outline and expand nodes by
introspection as needed.

It occurs to me that the same code could be used to search Leo's
runtime object hierarchy for you, i.e. you enter 'insertIconFromFile'
and it recursively searches for it.

Cheers -Terry

.. @+node:ekr.20130806211959.17330: *5* Re: How to call functions from LeoPyRef.Leo
From: Terry Brown <terry_n_brown@yahoo.com>

On Mon, 20 May 2013 08:47:35 -0500
Terry Brown <terry_n_brown@yahoo.com> wrote:

> On Mon, 20 May 2013 04:00:59 -0700 (PDT)
> Fidel P=E9rez <fidelperez@gmail.com> wrote:
>
> > Ok, in order to print icons, the code is this:
> >
> > c.editCommands.insertIconFromFile(path)
> >
> > Im quoting from this Leo manual<http://leoeditor.com/scripting.html#import-objects>,
> > "inserting and deleting icons" section -_-
> >
> > Although I still have a mess on which functions can be called how, and
> > where to find the list of classes that can be called such as "editCommands"
> > and the rest that they might exist.
>
> I'm not aware of a general solution to the problem of finding the
> various pieces of Leo's class structure.  Basically there are all these
> classes defined in the source, and instances of these are attached to
> each other in a hierarchical network (with loops).

I didn't really finish the above para.  The problem is that it's hard
to guess what the names of the attachment points are, and the attaching
is done in a variety of places, sometimes by factory functions which
further obscure linkages.  Not a fault with Leo, just the way programs
work.  So the tool I've written may be the best approach to mapping
Leo's runtime structure. Another thing it could do, try and map 'major'
classes, or at least classes from leo.core.* - i.e. ignore the built in
types.
.. @+node:ekr.20130806211959.17331: *4* How to make body text insertion at cursor permanent?
From: SegundoBob <bhossley@ieee.org>

This thread gives a recipe for inserting text into the body of a node
at the current cursor:

http://groups.google.com/group/leo-editor/browse_thread/thread/a08d122e0cf59359/60be2b02f3ef3e94

Unfortunately, this recipe has a problem:  When focus is moved away
from and then back to the modified node, the inserted text
disappears.  That is, Leo-Editor seems unaware of the insertion.

The following recipe fixes this problem:

http://pastebin.com/GAc15jRL

Is this recipe the right way to do it or is there a better way?
.. @+node:ekr.20130806211959.17332: *5* Re: How to make body text insertion at cursor permanent?
From: SegundoBob <bhossley@ieee.org>

I'm sorry no one has suggested a better way to make the changes
permanent.  How does Leo-Editor notice that typing has inserted a few
more characters?  Couldn't the same mechanism be used here?
.. @+node:ekr.20130806211959.17333: *5* Re: How to make body text insertion at cursor permanent?
From: Terry Brown <terry_n_brown@yahoo.com>

On Wed, 17 Apr 2013 12:09:52 -0700 (PDT)
SegundoBob <bhossley@ieee.org> wrote:

> This thread gives a recipe for inserting text into the body of a node
> at the current cursor:
> 
> http://groups.google.com/group/leo-editor/browse_thread/thread/a08d122e0cf59359/60be2b02f3ef3e94
> 
> Unfortunately, this recipe has a problem:  When focus is moved away
> from and then back to the modified node, the inserted text
> disappears.  That is, Leo-Editor seems unaware of the insertion.
> 
> The following recipe fixes this problem:
> 
> http://pastebin.com/GAc15jRL
> 
> Is this recipe the right way to do it or is there a better way?

I think that's the way, see also:

https://groups.google.com/forum/?fromgroups=#!searchin/leo-editor/insert$20text$20will$20disappear$20after$20insert$20children$20node$20and$20redraw/leo-editor/0haTWrUlNVg/lFU1JkMHrosJ

Depending on your use you might want to
   
    oldins = w.getInsertPoint() 

    ...

    w.setInsertPoint(oldins+len(inserted_text)) 

to get the cursor where you want it afterwards, lots of variations how
the new position might be calculated.

Other possibly useful methods:

    i,j = w.getSelectionRange(sort=True)
    s = w.getSelectedText()  
.. @+node:ekr.20130806211959.17334: *5* Re: How to make body text insertion at cursor permanent?
From: Terry Brown <terry_n_brown@yahoo.com>

On Wed, 17 Apr 2013 16:53:10 -0700 (PDT)
SegundoBob <bhossley@ieee.org> wrote:

> I'm sorry no one has suggested a better way to make the changes
> permanent.  How does Leo-Editor notice that typing has inserted a few
> more characters?  Couldn't the same mechanism be used here?

I don't think Leo constantly updates p.b from w.getAllText(), but just
does it when focus is lost - not sure about that though.

Here's a thought for a higher level interface.

c.get_edit_state() gives you an instance of a LeoEditState class with
these attributes:

  text attributes

  les.all_text
  les.text_before_select
  les.text_after_select
  les.selected_text
  les.text_before_cursor
  les.text_after_cursor

  integer attributes

  les.selection_start
  les.selection_end
  les.cursor_index

then you can either do

c.set_edit_state(les)

which sets the editor text and p.b to les.all_text and sets up
selection and insert position appropriately from the integers,

or c.set_edit_state(les, mode='selection')
or c.set_edit_state(les, mode='cursor')

which assembles things based on the selection or cursor text attributes.

Thoughts?  So long since I wrote any emacs text manipulation stuff I
can't remember the idiom it used.

Cheers -Terry



> On 04/17/2013 12:29 PM, Terry Brown wrote:> I think that's the way,
> see also:
> >
> > https://groups.google.com/forum/?fromgroups=#!searchin/leo-editor/insert$20text$20will$20disappear$20after$20insert$20children$20node$20and$20redraw/leo-editor/0haTWrUlNVg/lFU1JkMHrosJ
> >
> Thanks.  I vaguely remembered this thread, but I couldn't find it.
> 
> > Depending on your use you might want to
> >
> >     oldins = w.getInsertPoint()
> >
> >     ...
> >
> >     w.setInsertPoint(oldins+len(inserted_text))
> 
> http://pastebin.com/GAc15jRL  uses both w.getInsertPoint() and
> w.setInsertPoint()
> 
> >
> > to get the cursor where you want it afterwards, lots of variations how
> > the new position might be calculated.
> >
> > Other possibly useful methods:
> >
> >     i,j = w.getSelectionRange(sort=True)
> >     s = w.getSelectedText()
> 
> Yes, these are very useful.
> 
.. @+node:ekr.20130806211959.17335: *5* Re: the workflow of write leo scripts?
From: Terry Brown <terry_n_brown@yahoo.com>

On Fri, 12 Apr 2013 10:09:40 +0800
HaveF <iamaplayer@gmail.com> wrote:

> My workflow is like this
> [e.g., I want to select some text in the body and make transform, then
> insert to the body again]:

Your workflow make sense for the general case of doing any arbitrary
thing with Leo.  For the specific case of manipulating text, I think
the API could be improved, or, seeing the existing API make sense for
what it is, we could have additional "easy text manipulation" API.
So long since I used Emacs I can't really remember its model, and if it
would apply here.
.. @+node:ekr.20130806211959.17336: *4* How to use leo to make mathematical notes?
From: <lzyerste@gmail.com>

If I want to use leo to make mathematical notes, how can I type in some
special mathematical sysbols? Or is there a good way to make mathematical
notes using leo?

===== Terry

I use itex2MML with reStructuredText.  So within Leo you're looking at
LaTeX math markup, and you get outputs in PDF and XHTML, with MathML in
the latter.

===== <jose.i.rojas@gmail.com>

I've been doing this for about a year now.  I use the math docutils 
directive.  A custom .XCompose file (for example: 
https://github.com/kragen/xcompose)  also helps.

===== Terry

I think math was added to docutils after I started using itex2mml,
neater to use docutils built in math now I think.

Although having said that, playing with docutils math a bit suggests
itex2mml gives more complete support for both MathMML and perhaps LaTeX
math (with the PDF target).

===== jose

Terry, your setup is probably more flexible, but I haven't had any problems with 
docutils math. It seems to support all the syntax that I've found necessary.

I forgot to mention that the viewrendered plug-in doesn't display math 
correctly.  I'm not sure what the problem is, I remember trying to figure 
it out a while back, but I never got anywhere.  It's not really a big 
problem though, I have scripts to compile nodes to html/pdfs and open them 
in firefox/pdf reader; math works fine that way.

===== From: offray@riseup.net

Is not properly Leo, but is python related, tailored for math and with a
web interface and has leo bindings, check Ipython:

http://ipython.org/

I'm using it for all my math related writing and I think that point the
future of interactive writing in Python. I dream of a body pane on leo
with the features of the pyton qt console.
.. @+node:ekr.20130806211959.17337: *4* Indexing files for full text search
From: Terry Brown <terry_n_brown@yahoo.com>

Just pushed leo/external/leoftsindex.py:

Stand alone GUI free index builder for Leo's full text search system::

  python leoftsindex.py <file1> <file2> <file3>...

If <file> does not contain '#' it's assumed to be a .leo file
to index, and is indexed.

If <file> does contain '#' it's assumed to be a .leo file
containing a list of .leo files to index, with the list in
the node indicated by the UNL after the #, e.g.::

   path/to/myfile.leo#Lists-->List of outlines

In the latter case, if the node identified by the UNL has children,
the list of files to scan is built from the first line of the body
of each child node of the identified node (works well with bookmarks.py).
If the node identified by the UNL does not have children, the
node's body is assumed to be a simple text listing of paths to .leo files).

note::
    
    It may be necessary to quote the "file" on the command line,
    as the '#' may be interpreted as a comment delimiter::
        
        python leoftsindex.py "workbook.leo#Links"
.. @+node:ekr.20130806211959.17339: *4* Parameterized template nodes
From: Alexandre_Toledo <jalexandretoledo@gmail.com>

As I use Leo to write PL/SQL code, I need to write similar text several
times, changing only small parts of it. It would be great if I could create
a node with the "template" and then clone it everywhere it should be
written, and then providing the parameters to be used in this writing.

Let me try to clarify it. I'd like to create a tree like this:

 +- @file something.sql
           +- Section 1
              + << Clone >> with Parameters A, B
           +- Section 2
              + << Clone >> with Parameters C, D

In this tree, both "Clone" nodes would be generated from a template
specified somewhere in the tree, and would have parts of its text replaced
with values "A" and "B" in Section 1, and "C" and "D" in Section 2.

I've searched but couldn't find anything like this, then I've thought of
trying to write a hook to intercept the "save" command, but couldn't think
of a way to pass the parameters; I think the obvious way would be to put
the parameters after the "<< >>", but then all cloned nodes are changed, so
it wouldn't work.

Another alternative would be creating some kind of directive @something,
but I have no idea of how to do that.

Any ideas?
.. @+node:ekr.20130806211959.17340: *5* Re: Parameterized template nodes
From: =?UTF-8?Q?Fidel_P=C3=A9rez?= <fidelperez@gmail.com>



Content-Transfer-Encoding: quoted-printable

I know a programming IDE <http://sourceforge.net/projects/doublesvsoop/>which bases its existence in that concept:

You write "code Masks" and whenever you call a piece of code it will ask
only for the parameters, and write the rest of the code. There are already
some languages with most of the masks (all the primary functions and some
complex ones) and its growing.

For instance, if you write:

"window" it will add the window to the code and let you edit the params.

Their functionality would be awesome in Leo and when I know a bit better I
will try to emulate on it.
Sticking to Leo tho since it has a much superior way of managing data.


On Saturday, May 4, 2013 12:48:27 AM UTC+2, Jo=E3o Alexandre Toledo wrote:
>
> Hi,
>
> Sorry for the delay... I'll try it this weekend and see how it works.
>
> Thank you.
>
> Jo=E3o
.. @+node:ekr.20130806211959.17341: *5* Re: Parameterized template nodes
From: Terry Brown <terry_n_brown@yahoo.com>

On Sun, 5 May 2013 16:35:59 -0700 (PDT)
Fidel P=E9rez <fidelperez@gmail.com> wrote:

> I know a programming IDE <http://sourceforge.net/projects/doublesvsoop/>which bases its existence in that concept:
>
> You write "code Masks" and whenever you call a piece of code it will ask
> only for the parameters, and write the rest of the code. There are already
> some languages with most of the masks (all the primary functions and some
> complex ones) and its growing.

I suspect different people have different things in mind when they talk
about templates.

Leo's abbreviation system is already quite advanced when it comes to
filling in skeletons of common code layouts.  I type

  def;;

and I get

  def foo(this, that=3D3):
      """foo - Return
 
      :Parameters:
      - `this`: <|describe this|>
      - `that`: <|describe that|>
      """
 
      <|code|>

Two "parameters" are interactively requested, the function name, and
the list of arguments.  The node name is presented as the default for
the function name, and 'self' is included in the list of arguments, so,
assuming the node was already called 'foo', all I type is this, that=3D3.
The layout above is the rst form of the epydoc/sphinx docstring with
formally identified parameters.

The cursor is positioned after Return, where the was an empty <||>
placeholder.  Pressing ,, selects the next placeholder so that typing
replaces it.

There's more, see
https://groups.google.com/forum/?fromgroups=3D#!topic/leo-editor/5ni2PwfmBz8
and the screencast linked from there
http://www.greygreen.org/tmp/leoabbrev.ogv

Other people, Jacob etc. I think, have been talking about templates
where the input parameters are stored in the outline, allowing for
some of them to be altered and the template generation step re-run.
More like generating a website from data etc.

Cheers -Terry

.. @+node:ekr.20130806211959.17342: *5* Re: Parameterized template nodes
From: =?UTF-8?Q?Jo=C3=A3o_Alexandre_Toledo?= <jalexandretoledo@gmail.com>

Hi,

Sorry for the delay... I'll try it this weekend and see how it works.

Thank you.

Jo=E3o

.. @+node:ekr.20130806211959.17343: *5* Re: Parameterized template nodes
From: "Edward K. Ream" <edreamleo@gmail.com>

--001a11c27f4813f73804dbad029f

Content-Transfer-Encoding: quoted-printable

On Wed, Nov 21, 2012 at 8:55 AM, Jo=E3o Alexandre Toledo <
jalexandretoledo@gmail.com> wrote:

>
> As I use Leo to write PL/SQL code, I need to write similar text several
> times, changing only small parts of it. It would be great if I could create
> a node with the "template" and then clone it everywhere it should be
> written, and then providing the parameters to be used in this writing.
>

Variants of this seem to be wanted by many people.  Most recently, there is
the thread, "Templates with macro expansions",
https://groups.google.com/forum/?fromgroups=3D#!topic/leo-editor/nF2lUEUtaUE

Does that do what you want?

Edward

--001a11c27f4813f73804dbad029f

Content-Transfer-Encoding: quoted-printable

<div dir=3D"ltr">On Wed, Nov 21, 2012 at 8:55 AM, Jo=E3o Alexandre Toledo <span dir=3D"ltr">&lt;<a href=3D"mailto:jalexandretoledo@gmail.com" target=3D"_blank">jalexandretoledo@gmail.com</a>&gt;</span> wrote:<br><div class=3D"gmail_extra">
<div class=3D"gmail_quote"><blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><br><div>As I use Leo to write PL/SQL code, I need to write similar text several times, changing only small parts of it. It would be great if I could create a node with the &quot;template&quot; and then clone it everywhere it should be written, and then providing the parameters to be used in this writing.</div>
</blockquote><div><br></div><div>Variants of this seem to be wanted by many people.=A0 Most recently, there is the thread, &quot;Templates with macro expansions&quot;, <a href=3D"https://groups.google.com/forum/?fromgroups=3D#!topic/leo-editor/nF2lUEUtaUE">https://groups.google.com/forum/?fromgroups=3D#!topic/leo-editor/nF2lUEUtaUE</a><br>
<br></div><div>Does that do what you want?<br><br></div><div>Edward<br></div></div></div></div>

--001a11c27f4813f73804dbad029f--
.. @+node:ekr.20130806211959.17344: *5* Re: Parameterized template nodes
From: =?UTF-8?Q?Fidel_P=C3=A9rez?= <fidelperez@gmail.com>



Content-Transfer-Encoding: quoted-printable

Thank you Terry, that is exactly what I would like meant.

Is there a website where abbreviation files are shared so newcomers can
quickly being to use advanced abbreviations?
Id love to download a python version x)

On Monday, May 6, 2013 5:13:42 AM UTC+2, Terry wrote:
>
> On Sun, 5 May 2013 16:35:59 -0700 (PDT)
> Fidel P=E9rez <fidel...@gmail.com <javascript:>> wrote:
>
> > I know a programming IDE <http://sourceforge.net/projects/doublesvsoop/>which
> bases its existence in that concept:
> >
> > You write "code Masks" and whenever you call a piece of code it will ask
> > only for the parameters, and write the rest of the code. There are
> already
> > some languages with most of the masks (all the primary functions and
> some
> > complex ones) and its growing.
>
> I suspect different people have different things in mind when they talk
> about templates.
>
> Leo's abbreviation system is already quite advanced when it comes to
> filling in skeletons of common code layouts.  I type
>
>   def;;
>
> and I get
>
>   def foo(this, that=3D3):
>       """foo - Return
>  
>       :Parameters:
>       - `this`: <|describe this|>
>       - `that`: <|describe that|>
>       """
>  
>       <|code|>
>
> Two "parameters" are interactively requested, the function name, and
> the list of arguments.  The node name is presented as the default for
> the function name, and 'self' is included in the list of arguments, so,
> assuming the node was already called 'foo', all I type is this, that=3D3.
> The layout above is the rst form of the epydoc/sphinx docstring with
> formally identified parameters.
>
> The cursor is positioned after Return, where the was an empty <||>
> placeholder.  Pressing ,, selects the next placeholder so that typing
> replaces it.
>
> There's more, see
> https://groups.google.com/forum/?fromgroups=3D#!topic/leo-editor/5ni2PwfmBz8
> and the screencast linked from there
> http://www.greygreen.org/tmp/leoabbrev.ogv
>
> Other people, Jacob etc. I think, have been talking about templates
> where the input parameters are stored in the outline, allowing for
> some of them to be altered and the template generation step re-run.
> More like generating a website from data etc.
>
> Cheers -Terry
>
.. @+node:ekr.20130806211959.17345: *5* Re: Parameterized template nodes
From: =?UTF-8?Q?Jo=C3=A3o_Alexandre_Toledo?= <jalexandretoledo@gmail.com>



Content-Transfer-Encoding: quoted-printable

Hi,

I've tried it and it's great, I think it will be useful, but it's not what
I was thinking of...

Let me try to explain what I had tougth about... What I would like to do is:

 1. create a new .leo file
 2. add a "template" node (eventually with sub nodes) with some ${schema}
and ${table} macro place holders in its contents
 3. add a @file node to the .leo file
 4. add to this @file node a new one with definitions such as
schema=3DSCHEMA_NAME and table=3DTABLE_NAME
 5. add as a sub node to this last one a clone from the "template" node;
 6. then, when I save everything, the @file would have "SCHEMA_NAME" and
"TABLE_NAME" everywhere a "${schema}" or a "${table}" were in the original
template node.

It would be important that, when I reopen the .leo file later, the macros
in the @file node where shown as ${schema} and ${table}, and not as it's
substituted text.

Now that I've described it, I can't see how it would be done... The
${macro} place holders should be on the contents of the @file node, so
after substitution, how could we recover it?

That's also why the code from Jacob is not what I need (but I'm already
thinking of other uses for it :) ): it will create a text when the button
is pressed, but the generated nodes will be just static text.


Thank you all.

Leo is great!


Jo=E3o


On Friday, May 3, 2013 7:48:27 PM UTC-3, Jo=E3o Alexandre Toledo wrote:
>
> Hi,
>
> Sorry for the delay... I'll try it this weekend and see how it works.
>
> Thank you.
>
> Jo=E3o
.. @+node:ekr.20130806211959.17346: *4* Terry, how do you create the buttons with dropdown menus?
From: "Edward K. Ream" <edreamleo@gmail.com>

I have a note that it was an @rclick node handled by the context_menu.py 
plugin, but I am not able to see code or documentation anywhere.  This 
seems *well* hidden :-)
.. @+node:ekr.20130806211959.17347: *5* Re: Terry, how do you create the buttons with dropdown menus?
From: Kent Tenney <ktenney@gmail.com>

I don't have any visual indication of the existence of @rclick nodes,
it would be nice.

Something I've found useful is adding a @click node like:
@rclick -------------

that separates my entries from the ever present
'Remove Button' and 'Goto Script' entries
.. @+node:ekr.20130806211959.17349: *5* Re: Terry, how do you create the buttons with dropdown menus?
From: "Edward K. Ream" <edreamleo@gmail.com>

On Thu, Apr 11, 2013 at 8:10 PM, Edward K. Ream <edreamleo@gmail.com> wrote:

I prefer a bigger triangle:  =E2=96=BC U=3D25BC: Black Down-Pointing Triangle.

One more thing.  It's reasonable to have the top-level button just be a
placeholder for subsidiary @rclick nodes.  To do that without getting a
warning when clicking the top-level button, set its script to "empty
string".
.. @+node:ekr.20130806211959.17350: *5* Re: Terry, how do you create the buttons with dropdown menus?
From: Terry Brown <terry_n_brown@yahoo.com>

On Thu, 11 Apr 2013 00:56:51 -0700 (PDT)
"Edward K. Ream" <edreamleo@gmail.com> wrote:

> I have a note that it was an @rclick node handled by the context_menu.py 
> plugin, but I am not able to see code or documentation anywhere.  This 
> seems *well* hidden :-)

:) It's in the core, not context_menu.py.  It was a long time ago, but
I remember finding the @button code tricky, so I'm not sure if it's an
ideal implementation.  OTOH it hasn't broken for 1-2 years.

Cheers -Terry

.. @+node:ekr.20130806211959.17351: *5* Re: Terry, how do you create the buttons with dropdown menus?
From: "Edward K. Ream" <edreamleo@gmail.com>

On Thu, Apr 11, 2013 at 2:56 AM, Edward K. Ream <edreamleo@gmail.com> wrote:

One more thing.  I can now put an @rclick node under an @button node, and
right-clicking the created top-level button work pretty much as expected.

But I remember that on your machine there was some indicator (a triangle?)
in the top-level button indicating that it had structure.  Is that the
case?  If so, how did you create such buttons?
.. @+node:ekr.20130806211959.17352: *5* Re: Terry, how do you create the buttons with dropdown menus?
From: Terry Brown <terry_n_brown@yahoo.com>

On Thu, 11 Apr 2013 13:50:25 -0500
"Edward K. Ream" <edreamleo@gmail.com> wrote:

> On Thu, Apr 11, 2013 at 2:56 AM, Edward K. Ream <edreamleo@gmail.com> wrote:
>
> One more thing.  I can now put an @rclick node under an @button node, and
> right-clicking the created top-level button work pretty much as expected.
>
> But I remember that on your machine there was some indicator (a triangle?)
> in the top-level button indicating that it had structure.  Is that the
> case?  If so, how did you create such buttons?

@settings
   @string mod_scripting_subtext =3D =E2=96=BE
.. @+node:ekr.20130806211959.17353: *5* Re: Terry, how do you create the buttons with dropdown menus?
From: Terry Brown <terry_n_brown@yahoo.com>

On Thu, 11 Apr 2013 20:15:33 -0500
"Edward K. Ream" <edreamleo@gmail.com> wrote:

> On Thu, Apr 11, 2013 at 8:10 PM, Edward K. Ream <edreamleo@gmail.com> wrote:
>
> I prefer a bigger triangle:  =E2=96=BC U=3D25BC: Black Down-Pointing Triangle.
>
> One more thing.  It's reasonable to have the top-level button just be a
> placeholder for subsidiary @rclick nodes.  To do that without getting a
> warning when clicking the top-level button, set its script to "empty
> string".

I think you mean set its script to a docstring describing the
functions it groups together for the tooltip hover text :-)
.. @+node:ekr.20130806211959.17355: *5* Re: Terry, how do you create the buttons with dropdown menus?
From: "Edward K. Ream" <edreamleo@gmail.com>

On Thu, Apr 11, 2013 at 7:29 AM, Terry Brown <terry_n_brown@yahoo.com>wrote:

> On Thu, 11 Apr 2013 00:56:51 -0700 (PDT)
> "Edward K. Ream" <edreamleo@gmail.com> wrote:
>
> > I have a note that it was an @rclick node handled by the context_menu.py
> > plugin, but I am not able to see code or documentation anywhere.  This
> > seems *well* hidden :-)
>
> :) It's in the core, not context_menu.py.  It was a long time ago, but
> I remember finding the @button code tricky, so I'm not sure if it's an
> ideal implementation.  OTOH it hasn't broken for 1-2 years.
>

Thanks.  I could have sworn I searched Leo's core for @rclick.  Must have
been a searching failure :-)  The code is in
qtIconBarClass.setCommandForButton.

I'll add documentation for this, in leoSettings.leo and also in the
customizing Leo chapter.
.. @+node:ekr.20130806211959.17356: *4* the workflow of write leo scripts?
From: HaveF <iamaplayer@gmail.com>

I have read the scripting chapter of leo-editor, and already make my daily
life easier with these quick dirty, but useful scripts.

And I just want to know your workflow of writing leo scripts.

My workflow is like this
[e.g., I want to select some text in the body and make transform, then
insert to the body again]:

1. Abstract the action of word.
[in this case, I choose "select" and "insert" as my key words]

2. search the words at http://leoeditor.com/scripting.html see if there is
existing some related topics.
[I have luck to find
i = w.getInsertPoint()              # Return the location of the cursor.
...
i,j = w.getSelectionRange(sort=True)
...
s = w.getSelectedText()             # Return the selected text, if any.
]

3. but I still don't know how to insert the text to body. So I search the
above function names in the scripts.leo to see the code.
[ I find in
scripts.leo#Scripts-->@thin leoScripts.txt-->Text editing scripts-->insert
begin/endUpdate
...
w.insert(i,s1+'\\n\\t\\t\\n'+s2)
...
seems to help
]

4. test the scripts to see if it works, if it doesn't work, go to 3, to
find more example code.

Any suggestion to improve this workflow?
.. @+node:ekr.20130806211959.17357: *4* Tool for diffing Leo files
From: Terry Brown

The script below is a tool for diffing two Leo files. The attached
screenshot illustrates the output for two different revisions of
LeoPyRef.leo.

``- nodename``
    indicates a node which disappeared
``+ nodename``
    a node which is new,
``!v nodename`` followed by ``!^ nodename``
    a node with an unchanged heading but changed content, the first
    linking to the old version, the second linking to the new version

If you have the bookmarks.py plugin active, you can double click nodes
to jump to the original(s).



from leo.core.leoNodes import vnode
if not hasattr(vnode, 'insertAsLastChild'):
    # add insertAsLastChild method to vnodes
    def ialc(self):
        vnode(self.context)._linkAsNthChild(self, len(self.children))
        return self.children[-1]
    vnode.insertAsLastChild = ialc

from_filename = g.app.gui.runOpenFileDialog('From (old) file', [('Leo', '*.leo')])
to_filename = g.app.gui.runOpenFileDialog('To (new) file', [('Leo', '*.leo')])

# from_filename = "/mnt/shuttle/bkup/usr1/2012-07-13/home/tbrown/.leo/.todo.leo"
# to_filename = "/mnt/shuttle/bkup/usr1/2012-07-15/home/tbrown/.leo/.todo.leo"

from_c = g.openWithFileName(from_filename, c)
to_c = g.openWithFileName(to_filename, c)

vf = from_c.hiddenRootNode
vt = to_c.hiddenRootNode

assert from_c != c
assert to_c != c
assert from_c != to_c

nd = c.rootPosition().insertAfter()
nd.copy().back().moveAfter(nd)
nd.h = 'diff @bookmarks'

def text_match(a, b):
    return (a.h == b.h, 
            a.h == b.h and a.b == b.b)
def gnx_match(a, b):
    return (a.h == b.h and a.gnx == b.gnx, 
            a.h == b.h and a.b == b.b and a.gnx == b.gnx)

def diff_trees(vf, vt, path):

    fonly = []  # nodes only in from tree
    tonly = []  # nodes only in to tree
    diffs = []  # nodes which occur in both but have different descendants

    # count number of times each headline occurs as a child of
    # each node being compared
    count_f = {}
    for cf in vf.children:
        count_f[cf.h] = count_f.get(cf.h, 0) + 1
    count_t = {}
    for ct in vt.children:
        count_t[ct.h] = count_t.get(ct.h, 0) + 1

    for cf in vf.children:
        
        for ct in vt.children:
            
            if count_f[cf.h] == 1 and count_t[ct.h] == 1:
                equal = text_match
            else:
                equal = gnx_match
            
            head_eq, body_eq = equal(cf, ct)
            
            if body_eq:
                diffs.append(diff_trees(cf, ct, path+[vf.h]))
                
                break
            elif head_eq:
                d = diff_trees(cf, ct, path+[vf.h])
                if d:
                    d.h = '!v '+d.h
                else:
                    d = vnode(nd.v.context)
                    d.h = '!v '+cf.h
                d.b = "file://%s/#%s\\n\\n%s" % (
                    from_filename, 
                    '-->'.join((path+[vf.h]+[cf.h])[1:]),
                    cf.b
                )
                diffs.append(d)
                d = vnode(nd.v.context)
                d.h = '!^ '+cf.h
                d.b = "file://%s/#%s\\n\\n%s" % (
                    to_filename, 
                    '-->'.join((path+[vt.h]+[ct.h])[1:]),
                    ct.b
                )
                diffs.append(d)
                break
        else:
            fonly.append(cf)
            
    for ct in vt.children:
        
        for cf in vf.children:
            
            if count_f[cf.h] == 1 and count_t[ct.h] == 1:
                equal = text_match
            else:
                equal = gnx_match
            
            head_eq, body_eq = equal(cf, ct)
            if head_eq or body_eq:
                # no need to recurse matches again
                break

        else:
            tonly.append(ct)

    if not any(diffs) and not fonly and not tonly:
        return None
        
    vd = vnode(nd.v.context)
    vd.h = vf.h
    for d in diffs:
        if d:
            vd.children.append(d)
    for f in fonly:
        n = vd.insertAsLastChild()
        n.h = '- '+f.h
        n.b = "file://%s/#%s" % (from_filename, '-->'.join((path+[vf.h]+[f.h])[1:]))
    for t in tonly:
        n = vd.insertAsLastChild()
        n.h = '+ '+t.h
        n.b = "file://%s/#%s" % (to_filename, '-->'.join((path+[vf.h]+[t.h])[1:]))
        
    return vd

v = diff_trees(vf, vt, [])
if v:
    nd.v.children.extend(v.children)  # snip off <hidden root node>

c.bringToFront()
c.redraw()
.. @+node:ekr.20130806211959.17358: *5* Re: Tool for diffing Leo files
From: resi147 <scalet@yebu.de>




Hi Terry,

I tried this one and it seems to be very useful. What I would also like to 
have is a similar (or the same) script,
that does the same on two different nodes of a leo file. I admit, the 
changes should be minimal to be done by
myself, but as I'm not familiar with the internal leo api, I wanted to ask 
for how to best do this changes.

Probably somewhere here
"""
...
vf = from_c.hiddenRootNode 
vt = to_c.hiddenRootNode
...
"""
just to feed in the 2 nodes, Any quick idea how this can be done the best 
way?
.. @+node:ekr.20130806072439.20488: *4* Issue 1 with build 5752 (docutils & rst3)
From: Viktor Ransmayr <viktor.ransmayr@gmail.com>

now that you've 'cancelled' the 'leo/extensions/docutils' experiment I 
thought I investigate the status of '@rst' and 'docutils' again.

What I see in my local installation is the following:

<log>

Leo Log Window
Leo 4.11 devel, build 5752, 2013-04-27 11:55:26
Python 3.3.1, qt version 4.8.4
Windows 6, 1, 7601, 2, Service Pack 1
leoID=VR20100603 (in D:\\Users\\Viktor Ransmayr\\.leo)
load dir: D:\\Branches\\leo-editor\\leo\\core
global config dir: D:\\Branches\\leo-editor\\leo\\config
home dir: D:\\Users\\Viktor Ransmayr
reading settings in D:\\Branches\\leo-editor\\leo\\config\\leoSettings.leo
docutils loaded
reading settings in D:\\Users\\Viktor Ransmayr\\.leo\\myLeoSettings.leo
reading settings in D:\\Users\\Viktor Ransmayr\\Documents\\WL2013.leo
reading: D:\\Users\\Viktor Ransmayr\\Documents\\WL2013.leo

saved: WL2013.leo
created directory: D:\\Users\\Viktor Ransmayr\\Documents\\Logs\\2013\\04\\CW17
SilverCity not present so no syntax highlighting
Unexpected docutils exception
Traceback (most recent call last):
  File "D:\\Branches\\leo-editor\\leo\\core\\leoRst.py", line 1891, in 
writeToDocutils
    result = docutils.core.publish_string(source=s,
AttributeError: 'module' object has no attribute 'core'

</log>

Based on your current understanding: Should the '@rst' command with a 
properly installed 'docutils' package work in a Python 3 environment?

===== EKR

Yes it should, but in my experience installing docutils on Python 3
involves more (on Windows) than just doing setup.py install. I've had to do
the following:

- unpack docutils to a temp folder
- cd the temp folder
- python3 setup.py build
- 2to3 build
- copy the build\\lib\\docutils to your site-customize folder.

Note that you may have to set up a bat file to be able to execute 2to3
easily.

The easy way to see whether docutils is properly installed is to do F1.  If
you see::

*   Welcome to Leo's help system.*

Leo has loaded docutils properly. If you see::

    **Welcome to Leo's help system.**

then Leo could not load docutils.  In that case, Leo uses <pre> to format
help message.

===== lewis <lewisneal@operamail.com>

It may be useful to try the installation method suggested at 
http://docutils.sourceforge.net/README.html#installation
    
The introductory comment "Just double-click install.py. If this doesn't
work, try the following:" convinced me to try the steps 1,2,3 :)

So first I unpack the archive
1. Open a Command Shell, MS-DOS Prompt, or Console
2. cd to location of docutils folder:
3. Install the package:
   <path_to_python.exe>\\python setup.py install
   e.g. at prompt C:\\Python33\\python setup.py install

When installing docutils I've never had to use 'python3 setup.py build' or '2to3 build'.
I'm interested to know if this works for you on the next docutils snapshot.

===== EKR

I've just double-checked.  On  docutils-0.10 python33 setup.py install does
*not* work for me, but the following does work::

- unpack to a temp folder
- cd the temp folder
- python33 setup.py build
- copy temp/build/lib/docutils to python33/Lib/site-customize.

In other words, there is no need for a separate 2to3 step, but for me there
*is* a need to do python setup.py build.  YMMV.

===== Viktor

I have now found a reliable way to create the HTML documentation from my 
log-outline.

From my POV it indicates that there is a problem within 'leoRst.py'

If I have not executed F1 before, I get the one or more of the entries, 
that I have reported previously:

<log-1>

Unexpected docutils exception
Traceback (most recent call last):
  File "D:\\Branches\\leo-editor\\leo\\core\\leoRst.py", line 1891, in 
writeToDocutils
    result = docutils.core.publish_string(source=s,
AttributeError: 'module' object has no attribute 'core'
done

</log-1>

However of I have explicitely executed F1 *before*, the HTML file(s) get 
created, no matter at which level I call the command 'rst3':

<log-2>

wrote: D:\\Users\\Viktor 
Ransmayr\\Documents\\Logs\\2013\\05\\CW18\\LE-2013-05-01.html
done
wrote: D:\\Users\\Viktor 
Ransmayr\\Documents\\Logs\\2013\\05\\CW18\\LE-2013-05-01.html
done
wrote: D:\\Users\\Viktor 
Ransmayr\\Documents\\Logs\\2013\\05\\CW18\\CW18-Statistics.html
wrote: D:\\Users\\Viktor 
Ransmayr\\Documents\\Logs\\2013\\05\\CW18\\LE-2013-05-dd.html
wrote: D:\\Users\\Viktor 
Ransmayr\\Documents\\Logs\\2013\\05\\CW18\\LE-2013-05-01.html
done

</log-2>

To make it clear and explicit: When I execute F1 I now get the proper 
output starting with

*Welcome to Leo's help system.*

Hope this helps you finding the root cause of this issue.



.. @+node:ekr.20130503155210.24814: *3* Tutorials/Screencasts
@nocolor-node

Rewrite in screencast-script style:
- Docstrings for the most important plugins.
- All help-for-<topic> text.
- Leo's tutorials.

** Screencast style for plugins docstrings.
* Screencast style for help messages.
* Screencast style for tutorials.
* Create YouTube channel for Leo screencasts.

Topics:
- Minibuffer: alt-x, tab-completion.
- @button.
- @rclick
- Find/Change (done)
- execute-script.
- bookmarks.py.

.. @+node:ekr.20130807203905.16656: *4* A beautiful pattern for composing large strings
From: "Edward K. Ream" <edreamleo@gmail.com>

I continue to work feverishly on various aspects of static type checking.

That work lead to a discovery that may benefit you.  It's one of the most 
beautiful patterns I've ever created: it allows a program to simply and 
naturally build up huge strings without using any string operations.  
Generating an html file with minimal stress on the gc is an obvious 
application.  You could also say that the pattern creates a Pythonic way of 
using lisp-like algorithms, but more safely than in lisp.

Full details at the stc documentation page::
http://webpages.charter.net/edreamleo/stc/stc.html#a-beautiful-pattern-for-building-large-strings

.. @+node:ekr.20130807203905.16657: *5* Re: A beautiful pattern for composing large strings
From: "Edward K. Ream" <edreamleo@gmail.com>

On Wednesday, January 2, 2013 10:02:40 AM UTC-6, Edward K. Ream wrote:

ReportTraverser uses this pattern at rev 288.  It is a remarkable 
simplification.
 

> The revised r.div method will be something like::
>
>     def div(self,aList):
>         compute old and new indents
>         return [
>             <div>, with old indent,
>             aList, with new indent,
>             </div>, with old indent,
>         ]
>

This doesn't work!  aList won't have the proper indentation.  In 
particular, the following won't work::

    [['  ',z] for z in aList],

flatten_list will add the two spaces before the line, that is, before a 
newline. Instead, a hack is needed:

    return [
        div,
        join_list(aList,indent='  '),
        '\\n</div>'
    ]

The new 'indent' keyword tells flatten_list to add the given indentation 
(two spaces, here), to strings that start with a newline.  The new code in 
flatten_list is::

        for i,item in enumerate(aList):
            if leading:                  yield leading
            for s in flatten_list(item):
                if indent:
                    if s.startswith('\\n'):
                        yield '\\n'+indent+s[1:]
                    else:
                        yield s
                else:
                    yield s
            if sep and i < len(aList)-1: yield sep
            if trailing:                 yield trailing

The point is that the indentation must be "moved behind the newline".

Edward

.. @+node:ekr.20130807203905.16659: *5* Re: A beautiful pattern for composing large strings
From: "Ville M. Vainio" <vivainio@gmail.com>

This seems like a spiritual relative of "rope" data structure:

http://en.wikipedia.org/wiki/Rope_(data_structure)

http://www.sgi.com/tech/stl/Rope.html

===== EKR

Yes, there is a similarity. However, the real beauty of new pattern is the
flatten_list method. It's the combination of the lists and flatten_list
that gives the pattern real power. We've just seen how the 'indent' keyword
hack allows sophisticated processing of the lists. I wouldn't expect more
hacks to be needed, but I've been surprised before ;-)
.. @+node:ekr.20130807203905.16660: *5* Re: A beautiful pattern for composing large strings
On Tue, 1 Jan 2013 17:03:05 -0800 (PST)
"Edward K. Ream" <edreamleo@gmail.com> wrote:

> Generating an html file with minimal stress on the gc is an obvious 
> application.

Nice.  An HTML specific approach which avoids things like the
r.div_end() construct is the LXML element factory:
http://lxml.de/tutorial.html#the-e-factory

Cheers -Terry

.. @+node:ekr.20130807203905.16662: *5* Re: A beautiful pattern for composing large strings
From: "Edward K. Ream" <edreamleo@gmail.com>

On Thursday, January 3, 2013 3:28:52 AM UTC-6, Ville M. Vainio wrote:
>
> Yes, it's indeed an interesting pattern. 
>
> It would seem more useful in faster languages than python though; in 
> python, string operations (and gc) are faster in comparison to executing 
> other code, whereas in fast, more static languages (C++, Java, Go) avoiding 
> GC gives you great benefits (I saw 5x perf increase reported for some Go 
> app when eliminating GC).
>

Thanks for these remarks.  I've enjoyed thinking about them.  A few 
responses:

1. This is a smallish pattern--it can't change the world, except insofar as 
something beautiful changes the world.

2. Otoh, the pattern changes the way I think about lisp and lisp-like 
patterns.  That's not nothing. For the first time, it makes list-oriented  
programming pattern completely safe.  It does this because it doesn't 
matter what each component list contains, nor does it matter *at all* what 
the shape of any part of the tree is.  This makes the pattern completely 
flexible.

3. The pattern can be generalized.  The pattern I described uses a tree of 
component strings to describe a (large) resulting string.  But one can 
easily imagine using lists to hold anything at all (of whatever tree shape) 
and then use another version of flatten_list to compose results of other 
types.  Alternatively, rather than composing a result, the analog of 
flatten_list could process the tree of lists in other ways.  So the most 
general version of the pattern is:

A) The tree of lists can contain any data whatever, especially including 
None,
B) The "producers" (visitors) can create subtrees of whatever shape,
C) The analog of flatten_list is free to do anything whatever with the 
resulting tree.

I suspect that these features are what appeal to lisp programmers ;-)

4. I'm not sure whether the pattern is more useful in "faster" languages or 
not.  True, anything that helps a feeble language like C++ will seem useful 
:-)  But points 1-3 above have nothing to do with speed: they just make 
programming simpler, more flexible, more powerful and more fun.

Imo, gc issues are important both in Python and in C++.  For stc, the only 
way to get reproducible timing statistics for tests was to do the following 
before running the test::

    for z in (0,1,2): gc.collect(z)

The ReportTraverser class no longer contains *any* calls to string.join, so 
one could imagine that all strings used in the code would be interned.  The 
generated tree actually contains nothing but *references* to strings, and 
if all strings are interned the references will not themselves cause any 
new strings to be allocated.

Naturally, gc issues are even more important in language like C++ without a 
gc.  Lol.  The preceding paragraph is more important for C++ than in 
Python.  So yes, in this sense I agree with you completely that the pattern 
is more useful for "fast" languages than for Python.

Thanks, Ville, for provoking all these pleasant thoughts :-)
.. @+node:ekr.20130807203905.16663: *5* Re: A beautiful pattern for composing large strings
From: "Edward K. Ream" <edreamleo@gmail.com>

On Tue, Jan 1, 2013 at 9:48 PM, Terry Brown <terry_n_brown@yahoo.com> wrote:

> On Tue, 1 Jan 2013 17:03:05 -0800 (PST)
> "Edward K. Ream" <edreamleo@gmail.com> wrote:
>
> > Generating an html file with minimal stress on the gc is an obvious
> > application.
>
> Nice.  An HTML specific approach which avoids things like the
> r.div_end() construct is the LXML element factory:
> http://lxml.de/tutorial.html#the-e-factory
>

Beautiful.  With the list framework the revised r.div method would be
something like::

    def div(self,aList):
        compute old and new indents
        return [
            <div>, with old indent,
            aList, with new indent,
            </div>, with old indent,
        ]

An example of the pattern in use::

    return [
        ...
        r.div([
            contents of the div,
        ]),
        ...
    ]

Similarly for span, etc. Thanks for pointing this out.  This is too good to
ignore.  I'll do it soon.
.. @+node:ekr.20130807203905.16664: *4* All about clone conflicts
From: "Edward K. Ream" <edreamleo@gmail.com>

Some people seem to think that it is difficult to understand how Leo
handles "clone wars":  differing values for a cloned nodes that appear
in several external files.  That's not true.  The rule is::

    **The last clone that Leo reads wins.**

That is, for any cloned node C, Leo takes the value of C.h and C.b to
be the values specified by the last copy that Leo reads.

There is only one complication::

    **Leo reads the entire outline before reading any external
files.**

Thus, if C appears in x.leo, y.py and z.py, Leo will choose the value
for C in x.py or y.py, depending on which @<file> node appears later
in the outline.

Notes:

1. Whenever Leo detects multiple values for C when opening an outline, Leo
   creates a "Recovered nodes" tree. This tree contains all the various
   values for C, nicely formatted so that it is easy to determine where the
   differences are.

2. I've just refreshed my memory by looking at the code.  The relevant methods are:

    fc.getLeoFile # Reads the outline, then calls at.readAll to read all external files.
    at.indicateNodeChanged # Adds data to c.nodeConflictList
    cacher.reportChangedClone # Adds data to c.nodeConflictList
    fc.handleNodeConflicts # Creates "Recovered Nodes" node and its children.

3. The present code is the simplest code that could possibly work. There is
no way Leo is going to do AI in order to implement complex rules for which
clones are "more important" than others. Thus, if you use cross-file
clones, it is up to *you* to know these rules and handle any resulting
conflicts. Imo, the "Recovered Nodes" feature is a big step forward for
Leo, and makes it impossible to lose data unless you willfully refuse to
examine the data.
.. @+node:ekr.20130807203905.16665: *5* Re: All about clone conflicts
From: Joon Ro <joonpyro@gmail.com>

Thanks for the explanation. As a matter of fact, I was having hard time 
understanding this. 

I had my source file in a @shadow node, and then I had a backup of that 
file as @file node, which had clones of the nodes of the source @shadow 
file and some other codes that I stashed. 

Whenever I changed the source code externally with leo closed, when I open 
leo, it made recovered nodes. The problem was since @file was placed 
"later" in the outline, leo kept putting the new changes I made to old, 
instead of new.

Now I understand how this works. but I think in multiple external file 
cases, it would make more sense if leo checks the file modification time 
when it makes decision which node is new, instead of just depending on the 
order of files in the outline. In above case, it is natural for me to have 
actual source nodes on the top of the outline and backup nodes on the 
bottom. Please let me know what you think. 
.. @+node:ekr.20130807203905.16668: *4* Draft: unit-testing tutorial
From: "Edward K. Ream" <edreamleo@gmail.com>

The following is a first draft of a unit-testing tutorial.  It will form 
the basis of a new help-for-unit-testing command, and may also become the 
introduction to Leo unit-testing chapter.

All comments are welcome.  Please let me know if anything is unclear.

-----

Leo makes it easy to create and run unit tests from individual outline 
nodes or trees.

A node whose headline starts with @tests defines a unit test.

The body text of the @test node contains a **self-contained** unit test.

For example, this creates a complete unit test::

    @test fails  (headline)
    assert False (body text)

To run this test, select the @test node and do:
<alt-x>run-selected-unit-tests-locally.
Leo will create and run the unit test automatically.

To see all of Leo's unit testing commands, do:
<alt-x>run<tab>

Leo pre-defines 'c', 'g' and 'p' in unit tests just as in scripts.

For more details about unit testing, see: 
http://leoeditor.com/unitTesting.html

**Notes for Leo developers**

leo/test/unitTest.leo contains all of Leo's own unit tests.

Running all tests is not necessary.  Just select::

    Active Unit Tests

and then do Alt-4 (run-selected-unit-tests-locally).

**Note**: Some tests will likely fail on machines other than EKR's.
You only need to be concerned about unit tests that start failing after you 
make your changes.

.. @+node:ekr.20130807203905.16669: *4* Tutorials re plugins
contextmenu
screenshots
todo
valuespace
.. @+node:ekr.20120226183512.10195: ** Bugs
@language rest
.. @+node:ekr.20130908104426.11232: *3* Bug-tracker: High priority
https://bugs.launchpad.net/leo-editor/+bug/nnn
.. @+node:ekr.20130530110446.12450: *4* Fix syntax coloring bug involving multiple body editors
.. @+node:ekr.20130502102046.10578: *4* Crash deleting body editor
# Trying to delete a second body editor.

Traceback (most recent call last):
  File "c:\leo.repo\trunk\leo\core\leoCommands.py", line 560, in doCommand
    val = command(event)
  File "c:\leo.repo\trunk\leo\plugins\qtGui.py", line 2980, in deleteEditor
    name = w.leo_name
AttributeError: 'LeoQTextBrowser' object has no attribute 'leo_name'
.. @+node:ekr.20130908104426.11233: *4* 1022140 scroll problem in the body pane
https://bugs.launchpad.net/leo-editor/+bug/1022140
.. @+node:ekr.20130908104426.11234: *4* 1041906 underlying C/C++ object has been deleted
https://bugs.launchpad.net/leo-editor/+bug/1041906

I did the following: Ctrl-F, entered "Dream:". F3 several times. Deleted characters "Dream: " from a body. Changed the header from Diary to Dream.
F3

Leo Log Window
Leo 4.11 devel, build 5424, 2012-08-21 16:03:45
Python 2.7.2, qt version 4.7.4
linux2
setting leoID from os.getenv('USER'): 'bob02'
load dir: /home/ldi/bzr/LeoLatest/leo/core
global config dir: /home/ldi/bzr/LeoLatest/leo/config
home dir: /home/bob02
reading settings in /home/ldi/bzr/LeoLatest/leo/config/leoSettings.leo
reading settings in /home/bob02/.leo/myLeoSettings.leo
reading settings in /media/datw1/BobH Archive/RFD/2011/rfd1110.leo
reading: /media/datw1/BobH Archive/RFD/2011/rfd1110.leo

exception executing command
Traceback (most recent call last):
  File "/home/ldi/bzr/LeoLatest/leo/core/leoCommands.py", line 559, in doCommand
    val = command(event)
  File "/home/ldi/bzr/LeoLatest/leo/core/leoEditCommands.py", line 9803, in findTabFindNext
    self.findTabHandler.findNextCommand()
  File "/home/ldi/bzr/LeoLatest/leo/core/leoFind.py", line 1492, in findNextCommand
    self.findNext()
  File "/home/ldi/bzr/LeoLatest/leo/core/leoFind.py", line 702, in findNext
    self.showSuccess(pos,newpos)
  File "/home/ldi/bzr/LeoLatest/leo/core/leoFind.py", line 1330, in showSuccess
    c.endEditing() # 2011/06/10: A major bug fix.
  File "/home/ldi/bzr/LeoLatest/leo/core/leoCommands.py", line 8197, in endEditing
    c.frame.tree.endEditLabel()
  File "/home/ldi/bzr/LeoLatest/leo/plugins/baseNativeTree.py", line 862, in endEditLabel
    self.onHeadChanged(p)
  File "/home/ldi/bzr/LeoLatest/leo/plugins/baseNativeTree.py", line 893, in onHeadChanged
    self.closeEditorHelper(e,item)
  File "/home/ldi/bzr/LeoLatest/leo/plugins/qtGui.py", line 6570, in closeEditorHelper
    w.setCurrentItem(item)
RuntimeError: underlying C/C++ object has been deleted
--------------- End log pane ----------------

As you can see my Leo-Editor version is 5424.
openSUSE 12.1
Kernel Linux 3.1.10-1.16-desktop
XFCE desktop environment
.. @+node:ekr.20130806072439.20497: *4* ***Leo does not display all content of a node ...
From: Viktor Ransmayr <viktor.ransmayr@gmail.com>

even at the latest revision (rev. 5500) Leo does not display all content of 
larger nodes
- Larger nodes approximately defined as >= 150 lines ...

That is searching for example for a 'TO-DO' item just return this 
particular line w/o the
context  around. - Going up - or - down does not refresh the screen & 
content ...

I thought I could provide you with an outline, where this problem 
consistently shows up.
- However, whenever I trim the personal outline I'm using the problem 
disappears.

This problem is really annoying - and - I would gladly provide more input, 
but so far I
fail. - Any suggestion?

With kind regards,

Viktor

PS: For completeness here's the log from Leo's startup:

<log>

Leo Log Window
Leo 4.11 devel, build 5500, 2012-10-19 18:35:23
Python 3.2.2, qt version 4.8.0
Windows 6, 1, 7601, 2, Service Pack 1
leoID=VR20100603 (in D:\\Users\\Viktor Ransmayr\\.leo)
load dir: D:\\Branches\\leo-editor\\leo\\core
global config dir: D:\\Branches\\leo-editor\\leo\\config
home dir: D:\\Users\\Viktor Ransmayr
reading settings in D:\\Branches\\leo-editor\\leo\\config\\leoSettings.leo
reading settings in D:\\Users\\Viktor Ransmayr\\.leo\\myLeoSettings.leo
reading settings in D:\\Users\\Viktor Ransmayr\\Documents\\Leo-BR-r5500.leo
reading: D:\\Users\\Viktor Ransmayr\\Documents\\Leo-BR-r5500.leo

</log>
.. @+node:ekr.20130806072439.20498: *5* Re: Leo does not display all content of a node ...
From: Terry Brown <terry_n_brown@yahoo.com>

I can confirm that this type of bug is still present in 5500 also.

Yesterday I was noticing this:

 - editing a node (A)
 - create new node by accidentally hitting insert
 - delete new node immediately while still in headline edit mode using
   cut-node 
 - node A is displayed incorrectly, a line is missing, selecting the
   body restores the missing line

vs. the above but selecting the body of the inserted node, then
deleting it, in which case A is displayed correctly without selecting
its body.

Today (the outline's changed) it's not doing that, but I still
notice the difference between inserting and immediately deleting a node
(scroll position in A restored incorrectly), vs. inserting a node,
selecting its body, and then deleting it (scroll position in A restored
correctly).

So, there's some execution path difference between A being selected
after an inserted node is deleted immediately (still in headline edit
mode) vs. after selection of its body.

Not a very helpful report, but maybe the difference between deletion of
the node immediately and after selecting its body guides you to a
particular piece of code.
.. @+node:ekr.20130806072439.20499: *5* Re: Leo does not display all content of a node ...
From: resi147 <scalet@yebu.de>

I also have the same problem, using the official 4.10 final.
I.e. a couple of lines are missing in the node (the linecounter
increments and decrements but the cursor does not move).

Not sure what report could be useful.
I also feel like it occurs on larger body nodes.
.. @+node:ekr.20130806072439.20501: *5* Re: Leo does not display all content of a node ...
From: lewis <lewisneal@operamail.com>

Same issue for me has been occurring on a large node. Interestingly, I can
only reproduce the display error when 'Leo Log Window' is at bottom left
position which is my ''initial_split_orientation' setting (horizontal: body
pane to the right). I can use Window>Toggle Split Direction to correct the
initial display error.

For me, the display error always becomes evident at line 95. My line
numbers 95,96 are visible then skips to 118. Lines 97 thru 117 are not
displayed. It appears to be graphics performance time lag; if I return to
the file after having switched to another leo tab the previously invisible
lines are visible.

Leo Log Window
Leo 4.11 devel, build 5647, 2013-04-02 08:03:37
Python 3.3.1, qt version 4.8.4
Windows 6, 1, 7601, 2, Service Pack 1
.. @+node:ekr.20130806072439.20531: *4* *** (response to Leo does not display...) Styling in Leo
From: Terry Brown <terry_n_brown@yahoo.com>

(This is a response to the invisible line glitch, but not directly
related, so a new thread)

Rember this:

http://groups.google.com/group/leo-editor/browse_thread/thread/ee869a0a70f2d765

Some time ago I was working on styling Leo from a single top level
stylesheet using a mechanism similar to CSS classes, so instead of:
    
    # widget is active
    w.setStyle("QTextEdit { color: red; font-weight: bold; }")
    
    ...
    
    # widget is inactive
    w.setStyle("QTextEdit { color: black; font-weight: normal; }")
    
you'd have

    # widget is active
    w.setAttribute('active', True)
    
    ...
    
    # widget is inactive
    w.setAttribute('active', False)

and in the single global style sheet

    QTextEdit[active="true"] { color: red; font-weight: bold; }
    QTextEdit[active="false"] { color: red; font-weight: bold; }

This isn't a perfect example because if active == focused then you
could probably just use the pseudo-state :focus and let Qt do all the
work, and also Leo would .setStyle() a string defined in @settings, not
something hard coded.

Qt styles are different from CSS in that CSS has a single attribute,
`class`, which can contain a space separated list of tags, whereas Qt
has arbitrary attributes like the `active` I just made up above.
.. @+node:ekr.20130908104426.11235: *3* Bug-tracker: Medium priority
@language rest

https://bugs.launchpad.net/leo-editor/+bug/nnn
.. @+node:ekr.20130926053913.11562: *4* Hard (3)
.. @+node:ekr.20130908104426.11242: *5*  914221 bound method ViewRenderedController.updated (Hard)
https://bugs.launchpad.net/leo-editor/+bug/914221

Summary of a *long* discussion: this may be a docutils issue, and does not seem easy to fix.
.. @+node:ekr.20130805080841.21380: *5* 1222947 Javascript importer doesn't handle common idiom (Hard)
@language javascript

https://groups.google.com/forum/#!topic/leo-editor/dmC8iIKlF7g

Bug 
https://bugs.launchpad.net/leo-editor/+bug/1222947

Here is the test file::


    var express = require('express');
     
    var app = express.createServer(express.logger());
     
    app.get('/', function(request, response) {
    response.send('Hello World!');
    });
     
    var port = process.env.PORT || 5000;
    app.listen(port, function() {
    console.log("Listening on " + port);
    });
.. @+node:ekr.20130916105324.19894: *5* 1226353 @shadow does not retain outline structure properly (hard)
@language rest

https://bugs.launchpad.net/leo-editor/+bug/1226353

===== EKR

The most important problem is compatibility.  As I have just verified,
@shadow will work even if the private file does not exist,
but all outline structure will be lost.  Therefore, it may be best
not to try to read old (ver-4thin) files at all.

@shadow does not reload the following simple file correctly!

+ @shadow
   @others
  + child 1
    child 1.1

shadow files (the private files containing the sentinels) use the *old*
(#@+leo-ver=4-thin) sentinels, rather than the new (#@+leo-ver=5-thin)
sentinels.

The old sentinels don't have an explicit notion of nesting level; the new
sentinels do, so it would seem that the way to fix this problem is to use
new sentinels. However, this would be a major change to the inner workings
of the @shadow logic.
.. @+node:ekr.20130926053913.11563: *4* Minor (8)
.. @+node:ekr.20111222113610.10244: *5*  613153 unable to describe root directory on thumb drive
A very complex bug

See https://bugs.launchpad.net/leo-editor/+bug/613153
.. @+node:ekr.20111026091322.16498: *5*  869098 Context menu settings lost if save as used
See https://bugs.launchpad.net/leo-editor/+bug/869098

Hard?

I have a Leo file with settings for context menu:
    
@settings
   @data contextmenu_commands
       edit-headline Edit headline
          copy-node Copy Node
          cut-node Cut Node
          paste-node Paste Node

then these settings are lost if I save the leo file to a new name using
File - Save as
If I reload the leo file, they do return
.. @+node:ekr.20130908104426.11243: *5*  969391 setup.py confuses newbies
https://bugs.launchpad.net/leo-editor/+bug/969391

setup.py is necessary for creating Ubuntu packages, but it is *not*
necessary for installation. This confuses newbies a lot.

I'd like to move, rename or otherwise hide this file, but Ville says that's
not trivial to do:

QQQ
I need to research it. The change won't be free, as the debian tooling
(python-support) expects it to be called setup.py. I need to find a
workaround, but can't do it right now.
QQQ
.. @+node:ekr.20130908104426.11266: *5* 1193820 Focus change on tree pane after saving current Leo file
.. @+node:ekr.20130920055521.11282: *5* 1228099 Cancelling save of dirty untitled commander doesn't work with --ipython
@language rest

https://bugs.launchpad.net/leo-editor/+bug/1228099

The Ipython bridge doesn't seem to be working.

The examples in the IPython chapter seem to be out of date.
http://leoeditor.com/IPythonBridge.html

Requires that IPython work with Leo using the --ipython option.
.. @+node:ekr.20130806072439.20380: *5* auto-rst error? need more robust?
From: HaveF <iamaplayer@gmail.com>

When I use auto-rst import rst file, sometimes, the author write extra
characters which aren't harm, but the leo says it is a error...like this
one:

reading: @auto-rst README

Error: @auto did not import @auto-rst README perfectly
The clean-all-lines command may help fix whitespace problems
first mismatched line: 20 (original) = 20 (imported)

Original file...

  18 u'how the learning experiment went.\\n'
  19 u'Step 1: Create the dataset\\n'
  20 u'----------------------------\\n'
  21 u'From this directory, run\\n'
  22 u'python make_dataset.py\\n'

Imported file...

  18 u'how the learning experiment went.\\n'
  19 u'Step 1: Create the dataset\\n'
  20 u'--------------------------\\n'
  21 u'From this directory, run\\n'
  22 u'python make_dataset.py\\n'

inserting @ignore

errors inhibited read @auto
D:\\OpenCourses\\ufldl\\ref\\pylearn2\\pylearn2\\scripts\\tutorials\\grbm_smd\\README

reading entire file into @auto node.

reading: @edit README

finished

The problem is the line 20 has two extra '-', when I remove it manually,
the import works.

Do you have a better idea to do this than do it manually?

===== From: Terry Brown <terry_n_brown@yahoo.com>

On Sat, 18 May 2013 16:50:12 +0800
HaveF <iamaplayer@gmail.com> wrote:

> Original file...
> 
>   18 u'how the learning experiment went.\\n'
>   19 u'Step 1: Create the dataset\\n'
>   20 u'----------------------------\\n'
>   21 u'From this directory, run\\n'
>   22 u'python make_dataset.py\\n'

At first I thought that the rst was invalid, but the docs. say
  The underline/overline must be at 
  least as long as the title text. 
http://docutils.sourceforge.net/docs/user/rst/quickref.html#section-structure
so I guess it's not.  But leo has nowhere to store the length of the
underlining.  Also, this is related to the issue where Leo changes the
underline characters used, e.g. = -> - and * -> # etc.

I think the easiest solution is going to be to do the import and just
remove the @ignore afterwards, checking that there are no changes that
matter.  Perhaps the wording of the @ignore message could make it
clearer that the import may not have failed, but just needs checking.

===== HaveF <iamaplayer@gmail.com>


But in fact, the @auto-rst load this rst file like @auto, no @ignore node 
at all.

My import procedure is like this:
1. make a node name:
@auto-rst models.txt
2. right click it, and select "refresh from disk"


And I just find another problem...
If the rst file like this:

MLP
===

It also occurs error:

reading: @auto-rst models.txt

Error: @auto did not import @auto-rst models.txt perfectly
The clean-all-lines command may help fix whitespace problems
first mismatched line: 10 (original) = 10 (imported)

Original file...

   8 u'    :members:\\n'
   9 u'MLP\\n'
  10 u'===\\n'
  11 u'.. automodule:: pylearn2.models.mlp\\n'
  12 u'    :members:\\n'

Imported file...

   8 u'    :members:\\n'
   9 u'MLP\\n'
  10 u'====\\n'
  11 u'.. automodule:: pylearn2.models.mlp\\n'
  12 u'    :members:\\n'

inserting @ignore

errors inhibited read @auto D:\\OpenCourses\\ufldl\\ref\\pylearn2\\doc\\library\\models.txt

reading entire file into @auto node.

reading: @edit models.txt

finished

It says I need a extra "="...

I have attached this file, for someone has interest to reproduce the error.

.. @+node:ekr.20111014074810.15652: *5* Fix bug: viewrendered should work better when docutils does not exist
.. @+node:ekr.20120401144849.10037: *5* Fix installer problem
@language rest

Leo 4.10 final released
http://groups.google.com/group/leo-editor/browse_thread/thread/6f475b4c0c2d204a

EKR: One of these might work better.

; RequestExecutionLevel highest
; RequestExecutionLevel admin

From Viktor

> I tried to install Leo 4.10 final from Sourceforge via
"LeoSetup-4.10-final.exe". Since I have a bazaar-based Leo environment up
and running I tried to install this into a completely new separate user
account.

> After trying several variations it looks like that the "LeoSetup Script"
requires a Python installation which is available to all users and not just
to this one new separate account.

I assume by LeoSetup Script you mean LeoSetup-4.10-final.exe.

If you mean setup.py, you shouldn't use it.

> If this is done intentionally, what is the rationale for it.

It wasn't done intentionally. There may be an nsi option to get around this
problem, but I'm not sure about it. I'll look at this soon.
.. @+node:ekr.20130806072439.20485: *5* Whitespace when importing java file using @auto
Importing java file using @auto. How do I adjust Leo to ignore whitespace and indentation irregularities?
From: Eoin <eoinmccarthy@fastmail.fm>

I'm using @auto to import java files into my Leo project. I'm then cloning 
various methods as sub-nodes of new feature nodes. 
It's helping keep my development focussed - and is useful to look back and 
see what parts of the codebase I've worked on for each feature. 

However, the whitespace in the Java files isn't completely regular. In 
particular, debug logging is always placed in column 1 - regardless of the 
surrounding indentation. 
Other people are also working on these files, so I'd rather not mess with 
the established convention. 

As things stand, when Leo imports a file its outputting a bunch of error 
messages:
* error: underindented line. Extra leading whitespace will be added
* warning: intermixed blanks and tabs

The creation of the auto node goes fine - though the final result has an 
@ignore directive in its root node. 
When working, I just take the @ignore away and clone the methods I want to 
work on. 
The problem is when I close the Leo file and re-open it later on, the same 
errors occur during the building of the auto node and the previous cloned 
information is lost. 
To restart work on a feature, I need to reclone the appropriate nodes. Not 
a showstopper, but not ideal. 

I tried adjusting the info in the JavaScanner class in the core 
leoImport.py file as follows:

        self.blockCommentDelim1 = '/*'
        self.blockCommentDelim2 = '*/'
        self.blockDelim1 = '{'
        self.blockDelim2 = '}'
        self.lineCommentDelim = '//'
        self.lineCommentDelim2 = None
        self.outerBlockDelim1 = '{'
        self.outerBlockDelim2 = '}'
        self.classTags = ['class','interface']
        self.functionTags = []
        self.sigFailTokens = [';','='] # Just like c.
        self.strict=False

I deleted the pyc file and restarted Leo. A new pyc file appears, so the 
compiled to bytecode seems to be ok.

I was hoping the the setting of self.strict = False would allow the parsing 
to ignore the whitespace and indentation issues. 
I'm still getting the same errors though. 

Any help appreciated. I'm using Leo 4.10-final. 

===== EKR

There is no easy way to do this at present, but it's probably reasonable to
disable errors (and not add @ignore) for underindented comments for
non-strict languages.

Please file a wishlist bug for this.  Thanks.
.. @+node:ekr.20130908104426.11269: *3* Bug-tracker: wish-list
There are 42 wishlist items.  Some appear to be duplicates, or closely related.
.. @+node:ekr.20111125072438.10204: *4* 882243: (Wishlist) Clones sometimes not saved: change how @others works
See https://bugs.launchpad.net/leo-editor/+bug/882243

In Leo, I made this file:

@file test.txt
@others
.....test1
     test: these are clones
.....test2
     @others

      what is going on...?
..........test1 <--- this is cloned
          test: these are clones

The output file does not have the cloned node:

#@+leo-ver=5-thin
#@+node:bill.20111025150533.3528: * @thin test.txt
#@+others
#@+node:bill.20111025150533.3527: ** test1
test: these are clones
#@+node:bill.20111025150533.3529: ** test2
#@+others
#@-others

what is going on...?
#@-others
#@-leo

I don't think it is a conflict with @others; it is just that some files do not retain the clones that are displayed.

Here is the copied node:

<?xml version="1.0" encoding="utf-8"?>
<!-- Created by Leo (http://webpages.charter.net/edreamleo/front.html) -->
<?xml-stylesheet ekr_test?>
<leo_file xmlns:leo="http://www.leo-editor.org/2011/leo" >
<leo_header file_format="2"/>
<vnodes>
<v t="bill.20111025150533.3528" a="E"><vh>@thin test.txt</vh>
<v t="bill.20111025150533.3527"><vh>test1</vh></v>
<v t="bill.20111025150533.3529" a="E"><vh>test2</vh>
<v t="bill.20111025150533.3527"></v>
</v>
</v>
</vnodes>
<tnodes>
<t tx="bill.20111025150533.3527">test: these are clones
</t>
<t tx="bill.20111025150533.3528">@others
</t>
<t tx="bill.20111025150533.3529">@others

what is going on...?</t>
</tnodes>
</leo_file>

Here is the copied leo file:

<?xml version="1.0" encoding="utf-8"?>
<!-- Created by Leo (http://webpages.charter.net/edreamleo/front.html) -->
<?xml-stylesheet ekr_test?>
<leo_file xmlns:leo="http://www.leo-editor.org/2011/leo" >
<leo_header file_format="2" tnodes="0" max_tnode_index="0" clone_windows="0"/>
<globals body_outline_ratio="0.5" body_secondary_ratio="0.5">
 <global_window_position top="50" left="50" height="500" width="700"/>
 <global_log_window_position top="0" left="0" height="0" width="0"/>
</globals>
<preferences/>
<find_panel_settings/>
<vnodes>
<v t="bill.20111025150533.3528" a="E"
expanded="bill.20111025150533.3529,"><vh>@thin test.txt</vh></v>
</vnodes>
<tnodes>
</tnodes>
</leo_file>
.. @+node:ekr.20111216105907.10218: *5* My response: this is a wishlist item
Reposted from http://groups.google.com/group/leo-editor/browse_thread/thread/67a28984616d09c9
About bug 882243: clones sometimes not saved

I'd like to discuss this bug here, because I would like us all to be aware of the situation, and possible changes.

The surprise
=========

To paraphrase the original bug report, suppose we have the following @file tree:

+ @file test.txt
@others
  + node 1 (cloned)
    node 1 text.
  + node 2
     @others
    + node 1 (cloned)
       node 1 text.

As usual, lines preceded by "+" denote headlines: all other lines are body text.

The surprise is that the cloned node1 node is written to the external file only once (as a child of the root node) and hence does not appear as a (cloned) child of the node2 node when Leo next loads the @file tree.

History
=====

I would like to call this a wishlist item because the
present code quite intentionally writes *any* node
(including cloned nodes) only once. That is, the write code
sets a bit when writing a node, and @others ignores any
nodes with that bit set.

You could call this a bug in the @others write logic, but at
one time it was done explicitly and on purpose.

I don't remember why this was so, but I do remember it *was*
so. It may have been an artifact of Leo's old representation
of clones that used both vnodes and tnodes. tnodes no longer
exist in the one-node world that we have been living in for
several years, and it may well be time to revisit the
original design, but I would rather not do that just now
because there are several "real" bugs that need attention
asap.

Workaround
=========

Because this is an issue involving @others, you might assume
that a workaround involving sections would be possible. You
would be correct. The following file works as expected::

+ @file test.txt
<< node 1 >>
<< node 2 >>
  + << node 1>> (cloned)
     node 1 text.
  + << node 2 >>
     << node 1 >>
    + << node 1 >>(cloned)
       node 1 text.
.. @+node:ekr.20130806072439.20374: *4* aha moment when using leo script with @url, and feature request ;-)
From: HaveF <iamaplayer@gmail.com>

1. Aha Sometimes, I just wonder, I write a script (say, @button button-1)
in leo-file-A.leo, and reuse it by copy(ctrl+shift+c) the button to
leo-file-B.leo.

When I'm working on leo-file-B.leo, I may have ideas to improve the
@button button-1, but at that time(working on leo-file-B.leo), I may
forget where the original place of @button button-1 is. Even I store
the original scripts in the default workbook.leo is a tedious work to
deal with(open it, locate where the original script is, update it...)

But! After I add the @url at the first line of @button button-1, I can
decide if the improvements what I made on leo-file-B.leo's @button button-1
should or shouldn't be merged to the original and upstream @button
button-1(in leo-file-A.leo) easily by just a click.

And if I work on leo-file-C.leo, I want to use the same script, but I just
only remember I use the script in the leo-file-B.leo instead of original
place. With @url I can easily jump to original place, and copy it to
leo-file-C.leo.

Using @url in the leo script, I can make the scripts consistency and
diversity at same time.

Great! But, Wait, wait!

2. Feature request.  At this time, you can use this idea by comment the @url
line after jump. If @url isn't comment, the leo-editor will say...
SyntaxError: invalid syntax at the @url line.

Maybe it is a good idea to omit the @url line in the script when executing
script?

===== EKR

Yes.  I think this is a good idea.  A similar idea occurred to me when
looking at @rclick nodes.  At present, the context_menu plugin contains an
ugly hack:  it allows an @rclick node to *follow* an @button node.  This is
needed at present when the @button node contains @others: the @rclick node
can't be part of the script "pulled in" by @others.

It would be much more elegant to ignore @rclick nodes when computing the
script.  This would require a change to the @others logic, but I think it
is worthwhile.

===== Terry Brown <terry_n_brown@yahoo.com>

I do this kind of thing by keeping buttons in @files...

@file ~/.leo/gen  # general utility buttons
@file ~/.leo/dml  # tools for editing an XML dialect I use
@file ~/.leo/sql  # tools for editing SQL / interacting with server

so changes made in one outline are automatically propagated to other
outlines next time they're reloaded.  You just reference the files
in each outline where you want those buttons.

> 2. Feature request
> At this time, you can use this idea by comment the @url line
> after jump. If @url isn't comment, the leo-editor will say...
> SyntaxError: invalid syntax
> at the @url line.
> 
> Maybe it is a good idea to omit the @url line in the script when executing
> script?

This probably would make sense, already the scripting machinery is
ignoring things like @nocolor or @language cobol or @nowrap etc.

Maybe you could file a wish-list bug item for tracking.
.. @+node:ekr.20130806072439.20377: *4* An unexpected phenomenon(Using @url node) in @shadow
From: HaveF <iamaplayer@gmail.com>

When I use @url node in @shadow file, the node
should not be in public file, right?
.. @+node:ekr.20130806072439.20369: *4* @paragraph(s)
From: <offray@riseup.net>

I have been using txt2tags + Nested Editor to produce structured docs in 
a light markup and exporting them to HTML and LaTeX > pdf. The fine 
tunning on the pdf output is done by editing the LaTeX source in Leo. I 
like the aesthetic of the source code and the outputs and I have 
contacted the Nested author in order to get some cross-pollination 
between it and Leo [1].

[1] 
https://groups.google.com/group/nestededitor/browse_thread/thread/7068e3cd229d4614 

Now I think that is time to start hacking Leo for a better support of my 
work flow and the first thing I would like to have is a "@paragraph" 
directive that works the same as @rst-no-head but can be used in any 
part of a (sub)tree, even if is not @rst (sub)tree. This would come 
handy in chunking and reassembling LaTeX docs without marking up the 
parts with "<<chunk>>" tags.

===== EKR

Interesting idea. Please file a wishlist bug at https://bugs.launchpad.net/leo-editor.

===== offray As I have say repeatedly I'm an "end user" 
of Leo and I have browse the doc about developing in Leo in [2] and I 
plan to follow it as a tutorial, but any pointer to a more detailed 
section to pay attention or to the Leo trees to start hacking is welcomed

[2] http://webpages.charter.net/edreamleo/scripting.html

.. @+node:ekr.20130806072439.20523: *4* RST3 Tables with Nodes as Rows
From: Craig Johnson <craig@hivemind.net>

I'm trying to use rst tables by using the table markup in the body text, 
with one node per table row.  However it seems that the nodes are being 
preceded with a line-feed even-though @rst-no-head is in effect.
 
Can anybody help with preventing that line-feed, it breaks the rst table 
formatting.

===== EKR

Hmm.  My guess is that a new @rst directive would be needed.  The
workaround would seem to be to put the entire table in a single node, but
presumably you have your reasons for not wanting to do that.

Feel free to file a wish-list bug.

===== Craig Johnson <craig@hivemind.net>
 
I've been creating rst tables using rst markup directly in the body text.  
For field lists.  As the same field apears in multiple programs, I would 
like to use Leo's cloning to reproduce a table row in several locations in 
the tree.  The issue that prevents me from doing this, is that an 
@rst-no-head headline seems to generate a line-feed preceeding the body 
text in the derived file which breaks the table parse.
 
Maybe a example:
The Leo tree:
 
+Program1
  +Parameters
       =================== ========
       Field Name          Format
       =================== ========
    +@rst-no-head Field1
        prmField1          Integer
 
Results in the following markup
Program1
^^^^^^^^^
Parameters
~~~~~~~~~
=================== ========
Field Name          Format
=================== ========

prmField1           Integer
That blank line in the markup before the node body text breaks the table.
 
===== wgw <wgwinder@gmail.com>


No fix (sorry), but can confirm the problem -- it should go in the bug
list. (I looked at the rst code, and fainted)

I note that your format wouldn't work without closing the table off:


Field Name                       Format
 add                                    add

But you are right: @rst-no-head doesn't work properly.

Looks like you can only post process the rst intermediate file and=20
eliminate that extra line.
.. @+node:ekr.20130806072439.20387: *4* wishlist: Autosaving when external file saved
From: "Ville M. Vainio" <vivainio@gmail.com>

Just an idea:

After discovering sublime edit, I have started using external editor mode
more (rclick -> Edit in...). Annoyance there is that once you save in
external editor, you still have to go to leo and save there, or your
changes will be lost if you close leo without saving.

This can lead to loss of data if you don't routinely agree to save changes
when closing Leo. I often don't do this, as I save all the time when I
type, and don't want to save accidental changes I might have done to the
leo document; I don't usually have time to review changes when closing a
document.

Maybe .leo could automatically save the tree if and only if the externally
edited node is the only dirty one.

===== EKR

I agree there is a problem, but I don't believe hacking Leo's save logic is
a good idea, for several reasons:

1. There might be several dirty nodes, and you could still lose data
(strictly following your suggestion) in that case.

2. The write logic for external files is complex, mainly due to file
caching.  I tolerate that complexity because caching is such a big win.
But it would not be easy to do @file AI to discover the special case you
mention.

3. Imo, the proper place to handle this problem is in the vim and xemacs
plugins.  These plugins are responsible for the interaction with Leo.

Would it work for you if the xemacs and vim plugins automatically saved an
external file whenever the plugin caused a node in that file to become
dirty?  This would likely solve the problem you mention, although I
wouldn't be my life on it.

Your comments, please.

===== Matt Wilkie <maphew@gmail.com>

I've been bit by this several times too.

It's lead to me relying on pyscripter (my usual external editor these days,
has more useful to me command completion than leo) more and more, when I
otherwise might just nip out, do a few things and come back.

===== EKR

One thing that must be done in any case is to provide alt-x commands for
all context-menu entries.  There is something wrong with having to use the
mouse at all...

===== Terry Brown <terry_n_brown@yahoo.com>

Coincidentally I added the alt-X command 'context-menu-open' a week or
so ago, letting you open the context menu with a keyboard binding so
you can then navigate the menu with the cursor keys.

This is because not all menu entries can have alt-X commands,
specifically the quickMove plugins commands for moving nodes to
pre-defined destinations in other outlines, this is basically a list
selection operation, but being on a sub-sub-menu it's a pain with the
mouse, and easier with the cursor keys.

This is part of my method for handling todo items for different
projects, they are imported from email to one outline, and then I file
them to the relevant project outline's todo node.  Which creates a
management problem I just found a surprisingly viable solution for I'll
mention in another post.

===== From: "Ville M. Vainio" <vivainio@gmail.com>

I wouldn't change the save logic, I'd just execute "save" for the full .leo
document when

- Node has changed in external editor.
- The node that changed is the only dirty node in the whole leo document.

I don't use xemacs/vim plugin, but rather "edit in" in right click menu
(contextmenu.py plugin IIRC).

I agree that this is not an elegant proposal, in that it involves a
potentially surprising (if useful) special case.

I have to think this a bit more. Perhaps some kind of extra warning in the
UI for this scenario would do the trick as well.

.. @+node:ekr.20130806072439.20394: *5* Re: Autosaving when external file saved
From: "Edward K. Ream" <edreamleo@gmail.com>

On Thu, Nov 29, 2012 at 6:30 AM, Ville M. Vainio wrote:

> I wouldn't change the save logic, I'd just execute "save" for the full 
>> .leo document when 
>>
>> - Node has changed in external editor.
>> - The node that changed is the only dirty node in the whole leo document.
>>
>> I don't use xemacs/vim plugin, but rather "edit in" in right click menu 
>> (contextmenu.py plugin IIRC).
>>
>
> Ok.  In that case the contextmenu plugin should handle this. 
>

I believe that c.openWith should be able to deal with this problem.  
c.openWith creates a temporary external file and updates a node when the 
user changes that file.  This logic is independent of the editor being 
used; it works, for example, with Scite, my default external editor.

Clearly, c.openWith (or rather, one of its helpers) is able to update the 
node and to mark it dirty.  So at the time the node is marked dirty 
c.openWith has an opportunity to automatically save the file containing the 
vnode.  c.openWith can issue a colored message to the log pane, but that 
should be the only "warning" necessary.

My present plan is to write a helper, say c.write_vnode, that will discover 
the external file (if any) containing the vnode, and immediately write that 
external file *without* a prompt.  If there is no external file, 
c.write_vnode could just do an ordinary save of the .leo file and all dirty 
external files.  Alternatively, c.write_vnode could write only the .leo 
file (the write-outline-only command) *without* clearing the c.changed bit.

I believe c.write_vnode will solve this problem fairly completely.  What do 
you think, Amigos?

Edward
.. @+node:ekr.20130806072439.20395: *5* Re: Autosaving when external file saved
From: "Edward K. Ream" <edreamleo@gmail.com>

On Thu, Nov 29, 2012 at 9:17 AM, Edward K. Ream <edreamleo@gmail.com> wrote:

>
> Clearly, c.openWith (or rather, one of its helpers) is able to update the
> node and to mark it dirty.
>

The "helper" is the idle-time hook,  editnode_on_idle, in contextmenu.py.
You could call this good news, because our experiments with auto-saving can
be confined to the contextmenu plugin.  If our experiments end happily we
can use the same techniques in the vim and xemacs plugins.

I'll wait awhile for your comments before going ahead with the proposed
changes.
.. @+node:ekr.20130806072439.20396: *5* Re: Autosaving when external file saved
From: "Edward K. Ream" <edreamleo@gmail.com>

On Tue, Dec 11, 2012 at 5:55 AM, Ville M. Vainio <vivainio@gmail.com> wrote:

> """
> My present plan is to write a helper, say c.write_vnode, that will
> discover the external file (if any) containing the vnode, and immediately
> write that external file *without* a prompt.  If there is no external file,
> c.write_vnode could just do an ordinary save of the .leo file and all dirty
> external files.
> """
>
> Maybe a relatively safe solution is to do this:
>
> 1) My present plan is to write a helper, say c.write_vnode, that will
> discover the external file (if any) containing the vnode, and immediately
> write that external file *without* a prompt.
>
> But not do this:
>
> 2) If there is no external file, c.write_vnode could just do an ordinary
> save of the .leo file and all dirty external files.
>
> This way, if you "want to be safe", you will create an external @file for
> the content.
>
> For situation 2), some kind of loud warning is in order, not sure of what
> kind though. Red g.es?
>

Thanks for this suggestion.  I have a great distrust of all operations
containing "if" statements in their explanation.  Somehow, we need a
simpler approach, but I don't know what it is.

.. @+node:ekr.20130806072439.20397: *5* Re: Autosaving when external file saved
From: "Edward K. Ream" <edreamleo@gmail.com>

On Thu, Nov 29, 2012 at 6:30 AM, Ville M. Vainio <vivainio@gmail.com> wrote:

> I wouldn't change the save logic, I'd just execute "save" for the full
> .leo document when
>
> - Node has changed in external editor.
> - The node that changed is the only dirty node in the whole leo document.
>
> I don't use xemacs/vim plugin, but rather "edit in" in right click menu
> (contextmenu.py plugin IIRC).
>

Ok.  In that case the contextmenu plugin should handle this.

>
> I agree that this is not an elegant proposal, in that it involves a
> potentially surprising (if useful) special case.
>
> I have to think this a bit more. Perhaps some kind of extra warning in the
> UI for this scenario would do the trick as well.
>

I agree that if the code is going to do something like this it should issue
a clear warning that something has happened.  Otoh, such "clear warnings"
tend to get ignored :-)  Indeed, the problem is that you are *already*
ignoring such a clear warning!  Adding another warning is not likely to be
a big help...

Edward
.. @+node:ekr.20130806211959.17373: *4* wishlist: meld integration
From: Haroldo Stenger <haroldo.stenger@gmail.com>

I'm slowly trying to grok leo. I love meld, it's simply the best text
comparison I've ever seen. I wonder if a greater bit of integration between
meld and leo is possible, and in which ways. Undoubtedly calling it as an
external process is better than anything.
.. @+node:ekr.20120523092521.9907: *3* Minor bugs
.. @+node:ekr.20111125072438.10214: *4* Fix bug: Another @shadow bug (test4.leo) (maybe)
email:
http://mail.google.com/mail/#label/Leo%2FBugs/133ac31add8b2c6c

see attachment, shadow file won't get written correctly, and it won't reread
correctly too. Using leo-editor-snapshot- 201111090253.

Hopefully I will be able to look on some bugs myself, but don't know when. Needs
a bit of time, I am not very familiar with python.

===== EKR

Leo doesn't understand .jsp.  @shadow should refuse to work for unknown languages.
.. @+node:ekr.20111123095018.13632: *4* Fix bug: expand Find tab as needed for bigger fonts
.. @+node:ekr.20110605121601.18326: *5* createTab (leoQtLog)
def createTab (self,tabName,createText=True,widget=None,wrap='none'):
    """
    Create a new tab in tab widget
    if widget is None, Create a QTextBrowser,
    suitable for log functionality.
    """
    trace = False and not g.unitTesting
    c = self.c
    if trace: g.trace(tabName,widget and g.app.gui.widget_name(widget) or '<no widget>')
    if widget is None:
        widget = LeoQTextBrowser(parent=None,c=c,wrapper=self)
            # widget is subclass of QTextBrowser.
        contents = leoQTextEditWidget(widget=widget,name='log',c=c)
            # contents a wrapper.
        widget.leo_log_wrapper = contents
            # Inject an ivar into the QTextBrowser that points to the wrapper.
        if trace: g.trace('** creating',tabName,'self.widget',contents,'wrapper',widget)
        option = QtGui.QTextOption
        widget.setWordWrapMode(option.WordWrap if self.wrap else option.NoWrap)
        widget.setReadOnly(False) # Allow edits.
        self.logDict[tabName] = widget
        if tabName == 'Log':
            self.widget = contents # widget is an alias for logCtrl.
            widget.setObjectName('log-widget')
        # Set binding on all log pane widgets.
        if newFilter:
            g.app.gui.setFilter(c,widget,self,tag='log')
        else:
            theFilter = leoQtEventFilter(c,w=self,tag='log')
            self.eventFilters.append(theFilter) # Needed!
            widget.installEventFilter(theFilter)
        # A bad hack.  Set the standard bindings in the Find and Spell tabs here.
        if tabName == 'Log':
            assert c.frame.top.__class__.__name__ == 'DynamicWindow'
            find_widget = c.frame.top.leo_find_widget
            # 2011/11/21: A hack: add an event filter.
            if newFilter:
                g.app.gui.setFilter(c,find_widget,widget,'find-widget')
            else:
                find_widget.leo_event_filter = leoQtEventFilter(c,w=widget,tag='find-widget')
                find_widget.installEventFilter(find_widget.leo_event_filter)
            if trace: g.trace('** Adding event filter for Find',find_widget)
            # 2011/11/21: A hack: make the find_widget an official log widget.
            self.contentsDict['Find']=find_widget
            # 2013/09/20:
            if hasattr(c.frame.top,'leo_spell_widget'):
                spell_widget = c.frame.top.leo_spell_widget
                if trace: g.trace('** Adding event filter for Spell',find_widget)
                if newFilter:
                    g.app.gui.setFilter(c,spell_widget,widget,'spell-widget')
                else:
                    spell_widget.leo_event_filter = leoQtEventFilter(c,w=widget,tag='spell-widget')
                    spell_widget.installEventFilter(spell_widget.leo_event_filter)
        self.contentsDict[tabName] = widget
        self.tabWidget.addTab(widget,tabName)
    else:
        contents = widget
            # Unlike text widgets, contents is the actual widget.
        widget.leo_log_wrapper = contents
            # The leo_log_wrapper is the widget itself.
        if trace: g.trace('** using',tabName,widget)
        if newFilter:
            g.app.gui.setFilter(c,widget,contents,'tabWidget')
        else:
            theFilter = leoQtEventFilter(c,w=contents,tag='tabWidget')
            self.eventFilters.append(theFilter) # Needed!
            widget.installEventFilter(theFilter)
        self.contentsDict[tabName] = contents
        self.tabWidget.addTab(contents,tabName)
    return contents
.. @+node:ekr.20110605121601.18166: *5* createFindTab (DynamicWindow)
def createFindTab (self,parent,tab_widget):

    c,dw = self.leo_c,self
    grid = self.createGrid(parent,'findGrid',margin=10,spacing=10)
    grid.setColumnStretch(0,100)
    grid.setColumnStretch(1,100)
    grid.setColumnStretch(2,10)
    grid.setColumnMinimumWidth(1,75)
    grid.setColumnMinimumWidth(2,175)
    grid.setColumnMinimumWidth(3,50)
    # Aliases for column numbers
    col_0,col_1,col_2 = 0,1,2
    span_1,span_2,span_3 = 1,2,3
    # Row 0: heading.
    heading_row = 0
    lab1 = self.createLabel(parent,'findHeading','Find/Change Settings...')
    grid.addWidget(lab1,heading_row,col_0,span_1,span_2,QtCore.Qt.AlignLeft) # AlignHCenter
    # Rows 1,2: the find/change boxes, now disabled.
    find_row = 1
    change_row = 2
    findPattern = self.createLineEdit(parent,'findPattern',disabled=True)
    findChange  = self.createLineEdit(parent,'findChange',disabled=True)
    lab2 = self.createLabel(parent,'findLabel','Find:')
    lab3 = self.createLabel(parent,'changeLabel','Change:')
    grid.addWidget(lab2,find_row,col_0)
    grid.addWidget(lab3,change_row,col_0)
    grid.addWidget(findPattern,find_row,col_1,span_1,span_2)
    grid.addWidget(findChange,change_row,col_1,span_1,span_2)
    # Check boxes and radio buttons.
    # Radio buttons are mutually exclusive because they have the same parent.
    def mungeName(name):
        # The value returned here is significant: it creates an ivar.
        return 'checkBox%s' % label.replace(' ','').replace('&','')
    # Rows 3 through 8...
    base_row = 3
    table = (
        ('box', 'Whole &Word',      0,0),
        ('rb',  '&Entire Outline',  0,1),
        ('box', '&Ignore Case',     1,0),
        ('rb',  '&Suboutline Only', 1,1),
        ('box', 'Wrap &Around',     2,0),
        ('rb',  '&Node Only',       2,1),
        ('box', 'Search &Headline', 3,1),
        ('box', 'Rege&xp',          3,0),
        ('box', 'Search &Body',     4,1),
        ('box', 'Mark &Finds',      4,0),
        ('box', 'Mark &Changes',    5,0))
        # a,b,c,e,f,h,i,n,rs,w
    for kind,label,row,col in table:
        name = mungeName(label)
        func = g.choose(kind=='box',
            self.createCheckBox,self.createRadioButton)
        w = func(parent,name,label)
        grid.addWidget(w,row+base_row,col)
        setattr(self,name,w)
    # Row 9: help row.
    help_row = 9
    w = self.createLabel(parent,'findHelp','For help: <alt-x>help-for-find-commands<return>')
    grid.addWidget(w,help_row,col_0,span_1,span_3)
    # Row 10: Widgets that take all additional vertical space.
    w = QtGui.QWidget()
    space_row = 10
    grid.addWidget(w,space_row,col_0)
    grid.addWidget(w,space_row,col_1)
    grid.addWidget(w,space_row,col_2)
    grid.setRowStretch(space_row,100)
    # Official ivars (in addition to setattr ivars).
    self.leo_find_widget = tab_widget # 2011/11/21: a scrollArea.
    self.findPattern = findPattern
    self.findChange = findChange
    # self.findLab = lab2
    # self.changeLab = lab3
.. @+node:ekr.20110605121601.18156: *5* createGrid (DynamicWindow)
def createGrid (self,parent,name,margin=0,spacing=0):

    w = QtGui.QGridLayout(parent)
    w.setMargin(margin)
    w.setSpacing(spacing)
    self.setName(w,name)
    return w
.. @+node:ekr.20110605121601.18145: *5* createLogPane
def createLogPane (self,parent):

    # Create widgets.
    logFrame = self.createFrame(parent,'logFrame',
        vPolicy = QtGui.QSizePolicy.Minimum)
    innerFrame = self.createFrame(logFrame,'logInnerFrame',
        hPolicy=QtGui.QSizePolicy.Preferred,
        vPolicy=QtGui.QSizePolicy.Expanding)
    tabWidget = self.createTabWidget(innerFrame,'logTabWidget')

    # Pack.
    innerGrid = self.createGrid(innerFrame,'logInnerGrid')
    innerGrid.addWidget(tabWidget, 0, 0, 1, 1)
    outerGrid = self.createGrid(logFrame,'logGrid')
    outerGrid.addWidget(innerFrame, 0, 0, 1, 1)

    # 2011/10/01: Embed the Find tab in a QScrollArea.
    findScrollArea = QtGui.QScrollArea()
    findScrollArea.setObjectName('findScrollArea')
    findTab = QtGui.QWidget()
    findTab.setObjectName('findTab')
    tabWidget.addTab(findScrollArea,'Find')
    self.createFindTab(findTab,findScrollArea)
    findScrollArea.setWidget(findTab)

    spellTab = QtGui.QWidget()
    spellTab.setObjectName('spellTab')
    tabWidget.addTab(spellTab,'Spell')
    self.createSpellTab(spellTab)

    tabWidget.setCurrentIndex(1)

    # Official ivars
    self.tabWidget = tabWidget # Used by leoQtLog.
.. @+node:ekr.20111010162047.15678: *4* Fix bug: Imports to @file should put @first/@last directives in root node
Especially:
    - Shebang line.
    - Python encoding line.
    
- @auto correctly works for all Python files.
.. @+node:ekr.20111221102703.10289: *5* @@@nosent ../test/at-auto-at-first-test.py
#!/usr/bin/env python
# -*- coding: utf-8 -*-

def spam():
    pass
    
# This is the last line.
.. @+node:ekr.20120219152142.34262: *4* Fix bug: Revert moves the reverted tab to the right
.. @+node:ekr.20111125072438.10217: *4* Fix bug: shell interprets characters in at-mime headings
http://groups.google.com/group/leo-editor/browse_thread/thread/07efd66847ac4a64

on linux, parenthesis or angled brackets in @mime headings prevent the file from
being opened, probably because they are interpreted specially by the shell, e.g.
they need to be escaped. Such characters should be escaped before passing the
filename to the shell.

.. @+node:ekr.20120327163022.9744: *4* Fix bug: The @auto script *must* put @first nodes in root node
Also the import commands.

Especially:
    - Shebang line.
    - Python encoding line.
.. @+node:ekr.20111018104244.15920: *4* Fix bug: Use QLocalSocket in LProtoClient.connect
http://groups.google.com/group/leo-editor/browse_thread/thread/fe9cddc0e7ac8199
.. @+node:ekr.20120313134250.9852: *4* Fix nav_qt bugs
See: https://bugs.launchpad.net/leo-editor/+bug/820019
Shift-Ctrl-F (quicksearch) Sometimes leaves focus in body


See: https://bugs.launchpad.net/leo-editor/+bug/869385
Chapters make the nav_qt.py plugin useless.
.. @+node:ekr.20111026091322.16495: *4* Fix quickmove bug
See: https://bugs.launchpad.net/leo-editor/+bug/875463
Enabling quickmove.py sends to error messages to console on every outline open 
.. @+node:ekr.20111114085925.9932: *4* Why does the unittest/output folder contain empty files?
.. @+node:ekr.20031218072017.1462: *5* ic.exportHeadlines
def exportHeadlines (self,fileName):

    c = self.c ; p = c.p
    nl = g.u(self.output_newline)

    if not p: return
    self.setEncoding()
    firstLevel = p.level()

    try:
        theFile = open(fileName,'w')
    except IOError:
        g.warning("can not open",fileName)
        c.testManager.fail()
        return
    for p in p.self_and_subtree():
        head = p.moreHead(firstLevel,useVerticalBar=True)
        s = head + nl
        if not g.isPython3: # 2010/08/27
            s = g.toEncodedString(s,encoding=self.encoding,reportErrors=True)
        theFile.write(s)
    theFile.close()
.. @+node:ekr.20051104075904.78: *5* TM.makeImportExportSuite
def makeImportExportSuite(self,parentHeadline,doImport):

    """Create an Import/Export test for every descendant of testParentHeadline.."""

    tm = self
    c = self.c
    parent = tm.findNodeAnywhere(parentHeadline)
    assert parent,'node not found: %s' % (parentHeadline)
    temp = tm.findNodeInTree(parent,"tempNode")
    assert temp,'node not found: tempNode'

    # Create the suite and add all test cases.
    suite = unittest.makeSuite(unittest.TestCase)
    for p in parent.children():
        if p != temp:
            # 2009/10/02: avoid copy arg to iter
            p2 = p.copy()
            dialog = tm.findNodeInTree(p2,"dialog")
            assert(dialog)
            test = importExportTestCase(c,p2,dialog,temp,doImport)
            suite.addTest(test)
    return suite
.. @+node:ekr.20051104075904.79: *5* class importExportTestCase
class importExportTestCase(unittest.TestCase):

    """Data-driven unit tests for Leo's edit body commands."""

    @others
.. @+node:ekr.20051104075904.80: *6* __init__ (importExportTestCase)
def __init__ (self,c,p,dialog,temp_p,doImport):

    # Init the base class.
    unittest.TestCase.__init__(self)

    self.c = c
    self.dialog = dialog
    self.p = p.copy()
    self.temp_p = temp_p.copy()

    self.gui = None
    self.oldGui = None
    self.wasChanged = c.changed
    self.fileName = ""
    self.doImport = doImport

    self.old_p = c.p
.. @+node:ekr.20051104075904.81: *6*  fail (importExportTestCase)
def fail (self,msg=None):

    """Mark a unit test as having failed."""

    import leo.core.leoGlobals as g

    g.app.unitTestDict["fail"] = g.callers()
.. @+node:ekr.20051104075904.82: *6* importExport
def importExport (self):

    c = self.c ; p = self.p

    g.app.unitTestDict = {'c':c,'g':g,'p':p and p.copy()}

    commandName = p.h
    command = getattr(c,commandName) # Will fail if command does not exist.
    command(event=None)

    failedMethod = g.app.unitTestDict.get("fail")
    self.failIf(failedMethod,failedMethod)
.. @+node:ekr.20051104075904.83: *6* runTest
def runTest(self):

    # """Import Export Test Case"""

    self.importExport()
.. @+node:ekr.20051104075904.84: *6* setUp
def setUp(self):

    trace = False
    c = self.c ; temp_p = self.temp_p
    d = self.dialog
    assert(d)
    temp_p.setBodyString('')

    # Create a node under temp_p.
    child = temp_p.insertAsLastChild()
    assert(child)
    c.setHeadString(child,"import/export test: " + self.p.h)
    c.selectPosition(child)

    # Get the dialog name and the fileName from the dialog node.
    # This is used below to set up the dialog dict for nullGui.simulateDialog.
    s = d.bodyString()
    lines = s.split('\n')
    name = lines[0]
    fileName = lines[1]

    # Replace '\\' by os.path.sep in fileName
    try:
        # os.path.sep does not exist in Python 2.2.x.
        sep = os.path.sep
        fileName = fileName.replace('\\',sep)
    except AttributeError:
        fileName = g.os_path_normpath(fileName)
    self.fileName = fileName = g.os_path_finalize_join(g.app.loadDir,"..",fileName)
    if trace: g.trace('(importExportTestCase',fileName)
    
    # Set the dict for unitTestGui, a subclass of nullGui.
    # nullGui.simulateDialog uses this dict to return values for dialogs.
    if self.doImport:
        theDict = {name: [fileName]}
    else:
        theDict = {name: fileName}
    self.oldGui = g.app.gui
    self.gui = leoGui.unitTestGui(theDict,trace=False)
.. @+node:ekr.20051104075904.85: *6* shortDescription
def shortDescription (self):

    try:
        return "ImportExportTestCase: %s %s" % (self.p.h,self.fileName)
    except Exception:
        return "ImportExportTestCase"
.. @+node:ekr.20051104075904.86: *6* tearDown
def tearDown (self):

    c = self.c ; temp_p = self.temp_p

    if self.gui:
        self.gui.destroySelf()
        self.gui = None

    temp_p.setBodyString("")
    temp_p.clearDirty()

    if not self.wasChanged:
        c.setChanged (False)

    if 1: # Delete all children of temp node.
        while temp_p.firstChild():
            temp_p.firstChild().doDelete()

    g.app.gui = self.oldGui
    c.selectPosition(self.old_p)
.. @+node:ekr.20031218072017.2850: *5* c.exportHeadlines
def exportHeadlines (self,event=None):

    '''Export all headlines to an external file.'''

    c = self

    filetypes = [("Text files", "*.txt"),("All files", "*")]

    fileName = g.app.gui.runSaveFileDialog(
        initialfile="headlines.txt",
        title="Export Headlines",
        filetypes=filetypes,
        defaultextension=".txt")
    c.bringToFront()

    if fileName and len(fileName) > 0:
        g.setGlobalOpenDir(fileName)
        g.chdir(fileName)
        c.importCommands.exportHeadlines(fileName)
.. @+node:ekr.20130806072439.20371: *4* @wrap now suppresses horizontal scrolling
From: "Edward K. Ream" <edreamleo@gmail.com>

The title pretty much says it all.  This is a significant improvement, and 
makes Leo suitable for authoring text.  It should have been done ages ago. 
Please let me know immediately if this new behavior causes problems for you.

There is one glitch.  If you add @wrap, the directive won't be in effect 
until you leave the node and revisit it.

===== redla <radim.halir@gmail.com>

There is one problem which is (IMHO) caused by this change: I have @wrap 
active and see my "plain" text wrapped properly. But if there is any "long 
enough" URL on the page (i.e. longer than the screen width), this is not 
wrapped (as there is no space in the string) nor I can see the end of it 
(as there is no horizontal scrollbar either) ;-(

===== EKR

The workaround is to disable @wrap in order to see the url, but this is
clumsy.
.. @+node:ekr.20130806072439.20477: *4* Fix full-screen bug (works for me)
I can't make Leo-Editor start in a full-screen window under openSUSU 12.1

From: SegundoBob <bhossley@ieee.org>

I much prefer to almost always use Leo-editor in a full-screen window.   
When I run Ubuntu 11.10 with either the Fluxbox or the Gnome Classic 
sessions, when I re-open an outline that was last closed when its window 
was full-screen, Leo-Editor comes up in a full-screen window.  When I run 
openSUSE 12.1 with either the XFCE or IceWM sessions, Leo-Editor never 
comes up in a full-screen widow.  In all my tests I used exactly the same 
Leo-Editor for all operating systems and session managers.

Other applications can be made to come up in full-screen windows under 
openSUSE 12.1.  For example, Thunderbird and Thunar will come up in 
full-screen windows.

I have seen this problem with all of the following revisions of 
Leo-Editor:  5051, 5089, 5093, 5106, 5113, 5115, 5121, 5123, 5128, 5130, 
5138, 5141, 5143, 5147, 5148, 5161, 5166, 5200, 5220, 5248, and 5252.  I 
believe all my tests used Python 2.7.2, qt version 4.7.4.

Does anyone have any ideas about solving this problem?
.. @+node:ekr.20130806072439.20478: *5* "Re: I can't make Leo-Editor start in a full-screen window under openSUSU 12.1"
@nocolor

From: technatica <technatica@gmail.com>

1. Start Leo.
2. Ctrl-S
3. Close Leo.
4. Open Leo with window size saved.
.. @+node:ekr.20130806072439.20479: *5* "Re: I can't make Leo-Editor start in a full-screen window under openSUSU 12.1"
Have you filed an official bug for this?  If not, please do.

.. @+node:ekr.20130806072439.20480: *5* "Re: I can't make Leo-Editor start in a full-screen window under openSUSU 12.1"
From: technatica <technatica@gmail.com>

I have the exact same behaviour with Leo 4.10 final, build 5286,
2012-04-27 23:02:15.

It refuses to remember its window settings.

Arch Linux, 64bit, installed from bzr.

.. @+node:ekr.20130806072439.20481: *5* "Re: I can't make Leo-Editor start in a full-screen window under openSUSU 12.1"
From: SegundoBob <bhossley@ieee.org>

Doing a save does not help with my problem. I was already aware that some
parameters are only remembered when a save is done--and this is a minor
annoyance. Wouldn't it be better, more consistent, and more useable, if
every exit saved all the parameters that initialization restores?

The symptoms of my problem are that window sizes of less than full-window 
are remembered and restored, but when Leo-Editor is in full-screen at exit, 
then it is restarted in partial-screen mode with an arbitrary unused band 
at the top of the screen.
.. @+node:ekr.20110921094450.6956: ** Featues
@language rest

- Revisit some of the worst parts of Leo's code, especially undo and headline editing.
    
- Look at key-handling afresh, using minibuffer abbreviations.

- Allow abbreviations that insert nodes.

.. @+node:ekr.20111021105253.9478: *3*  First?
.. @+node:ekr.20120604071051.10187: *4* Add multiple body editors to session machinery
# Terry will do this, or help with it.
.. @+node:ekr.20120520055508.11873: *4* Add split-window commands
.. @+node:ekr.20111125072438.10219: *4* Open file dialogs starting with @path directory
@nocolor-node

File 'Open' or 'Import File' command to follow @path directive
http://groups.google.com/group/leo-editor/browse_thread/thread/7e508921c85d18bc

Suppose my focus node is under a @path directive, say @path E:
\Documents\Some Folder\

Is there a setting that would cause the 'File>Open' or 'File>Import
File' commands to begin the search dialog in the directory, E:
\Documents\Some Folder\ instead of the last directory used?

Would others find this a useful feature?
.. @+node:ekr.20111221114145.10217: *5* Found: runOpenFileDialog
# Important: many plugins use g.app.gui.openFileDialog.
.. @+node:ekr.20111026075003.16481: *4* Support ~/.leo_config.py
@language python
@language rest

1. Imo, it is time to consider adding a typical "startup" file to Leo,
~/leo_config.py, similar to ~/.emacs or ipython_config.py.  This will
make Leo "thicker", that is more professional/standard.

IPython adds lots of bells and whistles to configuration.  Leo
emulates most of them, but .leo_config.py would be a good addition.
Think of .leo_config.py as a lightweight plugin.

leo_config.py should execute after settings have been parsed, but
before plugins have been loaded.  If desired, leo_config.py may
register "start2" event handlers, which execute after all plugins have
been loaded, just before starting the main Qt event loop.

2. Leo commands form a good framework for other solutions to Qt
stylesheet issues.  Consider the following commands::

- qt-stylesheet-set-global-stylesheet
- qt-stylesheet-append-to-global-stylesheet
- qt-stylesheet-set-widget-stylesheet
- qt-stylesheet-append-to-widget-stylesheet

.. @+node:ekr.20111019104425.15868: *4* Render to tex, pdf, rst, etc.
.. @+node:ekr.20111003232155.6988: *4* Use c.db for marks & expansion bits
This would allow us to eliminate @bool put_expansion_bits_in_leo_files.
.. @+node:ekr.20130508084413.10631: *4* add g.etrace
.. @+node:ekr.20130508084413.10634: *4* quickmove-jump-to adds button
.. @+node:ekr.20120515193246.14289: *3* Code cleanup
.. @+node:ekr.20120208062900.10146: *4* Complete new_modes
@nocolor-node

This will eliminate the hacks for *entry-commands* and *command-prompt keys.

ModeController: a wrapper for g.app.config.modeCommandsDict

Clean up #### in leoKeys
.. @+node:ekr.20110528034751.18272: *4* Use free_layout to implement body editors
Collaborate with Terry.

A. Place separate body editors in free_layout areas. This should *easy* to
   do! Almost nothing changes in the code, but the visual effect should be
   much better.

B. Allow any pane to be "tabified" (placed in a tab in the Log pane) and
   "untabified." There are a few details to be handled, but nothing major.
   
C. Labels for panes.
.. @+node:ekr.20111125072438.10216: *4* Regularize slashes and back-slashes
@nocolor-node

http://groups.google.com/group/leo-editor/browse_thread/thread/0d48b507bc8ffc05

v4.9.1 build 4669
WinXP

If I 'Open' a file, I get the following node header:

@edit E:/Documents/index.html

If I 'Import' the same file, I get the following:

@file E:\Documents\index.html

Just wondering why the difference between

E:/ and E:\

This is probably trivial and of no consequence, but I thought it
curious.

Create unit tests illustrating path ops
.. @+node:ekr.20130503061707.10515: *5* @@test path computations
fj = g.os_path_finalize_join
f  = g.os_path_finalize
eu = g.os_path_expanduser

if g.app.isExternalUnitTest:
    loadDir = fj(g.app.loadDir,'..','test')
else:
    loadDir = g.app.loadDir

table = (
    (fj,'@@file fj-test-1',fj(loadDir,'rel-path')),
)

for func,h,expected in table:
    p = g.findNodeAnywhere(c,h)
    assert p,'not found: "%s"' % (h)
    assert p.h.startswith('@@')
    p.h = p.h[1:] # Remove the first @ sign.
    
    try:
        d = c.scanAllDirectives(p)
        result = d.get('path')
        assert result == expected,'expected "%s", got "%s"' % (
            expected,result)
    finally:
        p.h = '@' + p.h
        c.redraw()
.. @+node:ekr.20130503061707.10516: *6* @path rel-path
.. @+node:ekr.20130503061707.10517: *7* @@file fj-test-1
.. @+node:ekr.20130921043420.11270: *4* improve unit tests of class relationships
@language rest

- Use @testsetup to create smaller tests.
- Make sure leoBody follows HighLevelInterface?
.. @+node:ekr.20120527053550.12058: *3* Fun
.. @+node:ekr.20130806211959.17377: *4* Add coffeescript importer
From: "Edward K. Ream" <edreamleo@gmail.com>

Just yesterday I was looking into the CoffeeScript/XUL combination as
part of my study of FireBug. JQuery looks at first glance like a more
portable alternative.

As I write this, I realize that Leo would benefit from a CoffeeScript
importer.  I'll get on it :-)

.. @+node:ekr.20130602065849.14314: *4* Add tag handler
.. @+node:ekr.20081119132758.2: *4* Support @ifgui in settings trees
This can be done now that gui's are created on the command line.
.. @+node:ekr.20120527053550.10117: *4* Create find-def command
@nocolor-node

The find-def command (with ctrl-click support) would do
the hyperlinking.

It shouldn't be too hard: create an auto-completion-like popup if there are
multiple possibilities.  Use leoInspect.
.. @+node:ekr.20110620083705.14901: *4* Fix or disable curses gui
leoBridge.py requires the nullGui.
.. @+node:ekr.20130806072439.21203: *3* Ideas & wishlist
@language rest
.. @+node:ekr.20130806072439.21225: *4* * Distributed collaboration tool
From: Miles Fidelman <mfidelman@meetinghouse.net>

A big Leo fan pointed me at Leo, and this group - indicated that sharing 
Leo documents has been talked about over the years, but not really 
implemented, and suggested that I post some details about a project that 
I've been working on.  So....

Basic model is synchronized copies of documents, linked by an asynchronous 
pub-sub channel.  Think of a personal Wiki (like TiddlyWiki) - linked to 
copies of itself, that's the general idea.  Compose a document, email 
copies to collaborators, everyone saves a local copy - those copies link to 
each other via a pub-sub protocol to distribute updates.  All in 
JavaScript, embedded in the "smart documents" - nothing special to install.

If you're interested, details are at:
http://www.kickstarter.com/projects/1947703258/smart-notebooks-keeping-on-the-same-page-across-th
and Andy Oram wrote a background piece for O'Reilly Radar, at:
http://radar.oreilly.com/2012/08/smart-notebooks-for-linking-virtual-teams-across-the-net.html

I'd welcome comments, support, likes, tweets, blogs, ...

Thank you very much,

Miles Fidelman

EKR

My apologies for not responding sooner.  That was really unfortunate.  In
my experience, the best way to ruin good ideas is to ignore them :-(

As you may have gathered, I've been overwhelmed with good ideas, bugs that
should have been fixed years ago, sometimes pathetic or non-existent
documentation.  I'm getting less overwhelmed, but I won't be able to follow
up on this idea for now.

I encourage some of Leo's more web-aware users to take a look at this. For
now, I just have to file this under Leo/Ideas :-)
.. @+node:ekr.20130806072439.21204: *4* Comparison leo outline type with other outliner's types?
From: Todd Mars <tamnt54@gmail.com>

I remember reading -somewhere- about comparing various multi-parent or
multi-copy of node outline types (clones vs. backlinks or whatever) but I
can't find where I read that. Where is it? Desire to read analysis, isn't
that in the leo docs somewhere?

Terry

Personally I think Leo could navigate cyclic graphs, see
http://leo.zwiki.org/GraphsInTrees particularly the 'Older notes' section
towards the end. But it's a major issue with regard to all the algorithms
which don't expect to run in to loops. And the extra layer of connections
from the backlinks plugin allows the same functionality, so it may be that
it's more an interface issue than a data model issue.

I'd like Leo to be able to behave like CmapTools, http://cmap.ihmc.us/ but
maybe it can, essentially, and it's really a matter of defining some new
interface bells and whistle's.
.. @+node:ekr.20130806072439.21241: *4* Free range body editors
From: Terry Brown <terry_n_brown@yahoo.com>

I suspect that if body editors could be made just slightly more
flexible it would open up whole new ways of using Leo.  It seems they
just need two or three things to make them really flexible.

- a flag to indicate whether the tree pane should select the body
    editor's node when the body editor is focused.  To see an
    example of editing bodies without the tree selecting the node you're
    editing, see the stickynotes plugin

 - a flag to indicate whether the body editor should track the node
   currently selected in the tree

 - it needs to not care about what it's contained in, GUI wise.  I
   don't know how much work's involved in this.

I'll try and contribute to things moving in this direction when I have
time, just throwing it out there for others to think on.

If you could have a body editor edit the node indicated by an UNL, it
would basically be a clone...

.. @+node:ekr.20130806072439.21248: *4* Idea/needed: system command queue
From: "Ville M. Vainio" <vivainio@gmail.com>

Often, I find myself wanting to execute system commands in serial fashion
(first in, first out), capture their output, and allow browsing it, BUT not
blocking Leo or ipython terminal.

I'd like to show stderr and stdout in g.es, or separate log page, and
provide callback after task has been completed.

Unless anyone has something like this already, I plan to create it "later"
with QProcess.

===== Ville

Now I have basic functionality pushed to trunk.

If you want to "spawn" (posibbly several) system commands to background,
use g.procs.add(), like this ctrl+b script:

def L(*args):
    g.es("callback", args)

g.procs.add(['sleep', '4'], "que1")
g.procs.add(['sleep', '3'], "que1", L)
g.procs.add(['sleep', '2'], "que1")
g.procs.add(['sleep', '2'], "que2")

Note how que2 completes first. Idea is that commands in same queue depend
on each other, and thus need to run in sequential order.

This should make waiting for long lasting operations easier as the whole
Leo won't freeze until they are over (but you can still use the stdout /
stderr output from these calls, thanks to the optional callback)

API may change once I start using it (soon).

===== Terry

There's the leoscreen stuff for integration with the GNU `screen`
terminal switcher / manager.  Push lines from the body to the terminal,
pull lines back the other way.  But more for interactive interaction
with terminal programs than batch oriented work.  Leo doesn't block.

===== Ville

A challenge I can imagine with the "screen" workflow is detecting when a
command has been executed (and capturing stderr/stdout). Do you have a
solution for that in mind?

===== Terry

I tried more direct communication (subprocess.Popen.communicate())
before the screen approach, it's hard and probably app. specific.
leoscreen avoids that by basically being interactive, so it might not
be a fit for your case.  Basically it's leveraging the intelligence of
the user to keep track of execution.
.. @+node:ekr.20130806072439.21254: *4* Idea: easy key bindings
From: "Ville M. Vainio" <vivainio@gmail.com>

Problem: I find myself repeating a bunch of alt-x commands in the same
document. There is more than one, so ctrl-p (repeat last command) is not
useful.

Idea: specify that keys from alt-1 to alt-9 are "easy macro keys". They
would be easy to bind to various alt-x command without editing preferences.

How they can be bound:

Do e.g. alt-x ipython-exec

BUT instead of pressing ENTER in the end, press alt-1. This would bind the
command to alt-1.

Store them it c.db, so they will be remembered for every leo document, but
won't clutter bindings of other people editing the same file.

===== Matt

From: Matt Wilkie <maphew@gmail.com>

I often find myself in the same situation with regards to clipboards. If
alt-# were macros, ctrl-# could be clipboards perhaps?

It could be even more important then to have some sort UI method for
inspecting/previewing the contents of them. Maybe thumbnail preview a la
Sublime's right hand document overview.

===== Fidel

I am still studying (and have much more to study yet) Leo, but I think that 
two things can be archieved by integrating it with libraries like pywinauto 
<https://code.google.com/p/pywinauto/> or
dragonfly<https://code.google.com/p/dragonfly/>


- First of all, it could track all the keystrokes of the user, relate it to
  the window, then offer the user possibility to repeat (even complex
  sequences)

- Second, It would be great to have a Leo tab with buttons showing the
  hotkeys related to the current action (IE when the user has the cursor on
  a node, or the edit pane, etc) (or even the current window in front). So
  when the user uses those hotkeys, Leo will track them, so the next
  scenario could happen:

User copyes a link from Leo
User sets an excel file to front
User pastes it in an excel cell and hits down.

If both the user did those through hotkeys, and they were tracked, Leo 
could automatically offer repeat the same action with the next links held 
in the same category.

This is a pretty raw explanation but I hope it makes the point. 
Nevertheless, I will continue to study, research and try to help with those 
features by myself.
.. @+node:ekr.20130806072439.21299: *4* Leo and IPython
From: Kent Tenney <ktenney@gmail.com>

The ipython integration is great, any chance of connecting the the web notebook?

# ipython notebook

then, from the ipython dashboard in browser, click to open a notebook

the console reports:
[IPKernelApp] To connect another client to this kernel, use:
[IPKernelApp] --existing kernel-a25b19a2-55d6-43a2-aa05-dfeffb55136b.json

could <ctl-x> push-to-ipython send the contents of current Leo node
to the current cell in the ipython notebook?

It would be great to be able to jump between Leo's nodes and IPython's
cells, each offering a different set of cool functionality.

===== From: Alia K <alia_khouri@yahoo.com>

Incidentally look at this recent IPEP (Ipython Enhancement Proposal)
which allows for leo like cell-level directives (which in Ipython are
called magic commands): https://github.com/ipython/ipython/issues/1611

Leo + Ipython notebook integration is a killer app indeed.
.. @+node:ekr.20130806072439.21301: *4* Leo doc-generation and Wiki integration - GitIt and Pandocs
From: HansBKK <hansbkk@gmail.com>

This is highly off-topic for most on the list, so feel free to ignore, but 
anyone using Leo for single-source documentation generation/conversion, 
including future googlers, please reply with comments or notes on your 
experiences.

I have been advocating the idea of pushing Leo-derived content to DokuWiki 
as a platform for "wiki-publishing" to enable collaborative/community 
editing of content (1 <../d/msg/leo-editor/fSzVi1Rh5Tg/uu85satgb9YJ>, 2<../d/msg/leo-editor/xf6_HBxlV_c/4RgGYdDh8ywJ>). 
I've also talked about the markup syntax/doc generation tool Txt2tags (1<https://groups.google.com/d/msg/leo-editor/nNEnxoohFBM/XkMPQhqhDRsJ>, 
2 <https://groups.google.com/d/msg/leo-editor/HBhBnAyVG3E/UXHC1jq50iYJ> ).

However, I have recently learned of the wiki platform Gitit<https://github.com/jgm/gitit#readme>, 
which apparently, like DW, also uses plain-text files rather than a 
database back-end, and integrates not only with git but mercurial (and 
darcs).

Gitit also incorporates the Pandoc <http://johnmacfarlane.net/pandoc/>project for its markup syntax, therefore enabling not only markdown but 
reST as a master source input format, while DokuWiki has its own (yet 
another unique) markup syntax 8-( 

With the increasing likelihood that I'll be using Leo as the centerpiece of 
my toolchain, plus the fact that Pandoc is much more actively maintained, 
it's starting to look worth my while to consider switching my "master 
source" content syntax over from Txt2tags to reST. The only downsides are 
that Gitit is a Haskell project rather than Python, and one thing I like 
about Txt2tags is its support for conversion to AsciiDoc, rather than 
Pandoc's direct output to full-blown DocBook XML - but apparently even 
that's in the works in Pandoc's dev version.

Anyone in the Leo community using Gitit, especially for use beyond simple 
code documentation?
.. @+node:ekr.20130806072439.21302: *5* Re: Leo doc-generation and Wiki integration - GitIt and Pandocs
From: "Edward K. Ream" <edreamleo@gmail.com>

On Thu, Jan 19, 2012 at 8:09 PM, HansBKK <hansbkk@gmail.com> wrote:
> This is highly off-topic for most on the list, so feel free to ignore, but
> anyone using Leo for single-source documentation generation/conversion,
> including future googlers, please reply with comments or notes on your
> experiences.

No experience myself, but thanks for these interesting links.

EKR
.. @+node:ekr.20130806072439.21303: *5* Re: Leo doc-generation and Wiki integration - GitIt and Pandocs
From: =?UTF-8?B?T2ZmcmF5IFZsYWRpbWlyIEx1bmEgQ8OhcmRlbmFz?= <offray@riseup.net>

Hi,

I made some errors.

In this part:

El lun 23 ene 2012 07:22:21 COT, Offray Vladimir Luna C=E1rdenas escribi=F3=
:
>
> but at the end we could not intervene MoinMoin as much as we would=20
> like because of the server permissions, that why I started to look=20
> more integrated solutions of the development and deployment=20
> environment as web2py or seaside, but they're not wiki engines=20
> properly but web application frameworks (where you could build a=20
> wiki-engine if needed). But surely
>

"But surely" was not intended.

Cheers,

Offray

.. @+node:ekr.20130806072439.21304: *5* Re: Leo doc-generation and Wiki integration - GitIt and Pandocs
From: <offray@riseup.net>

El jue 19 ene 2012 21:09:26 COT, HansBKK escribi=F3:
> This is highly off-topic for most on the list, so feel free to ignore, bu=
t
> anyone using Leo for single-source documentation generation/conversion,
> including future googlers, please reply with comments or notes on your ex=
periences.

I'm using Leo in that scenario (for writing my Thesis and I hope my=20
students will use it in a similar fashion), so is not off-topic for me=20
and not for people who is using Leo primary for documentation.

> I have been advocating the idea of pushing Leo-derived content to DokuWik=
i as a
> platform for "wiki-publishing" to enable collaborative/community editing =
of
> content (1<../d/msg/leo-editor/fSzVi1Rh5Tg/uu85satgb9YJ>, 2
> <../d/msg/leo-editor/xf6_HBxlV_c/4RgGYdDh8ywJ>). I've also talked about t=
he
> markup syntax/doc generation tool Txt2tags (1
> <https://groups.google.com/d/msg/leo-editor/nNEnxoohFBM/XkMPQhqhDRsJ>, 2
> <https://groups.google.com/d/msg/leo-editor/HBhBnAyVG3E/UXHC1jq50iYJ>  ).


When you suggested DocuWiki I thought of MoinMoin which has also=20
support of plain files as storage mechanism but is also scalable to=20
databases if this is needed and it supports reStructuredText and is=20
made in python, a language that "leonizens" are familiar with.

> However, I have recently learned of the wiki platform Gitit
> <https://github.com/jgm/gitit#readme>, which apparently, like DW, also us=
es
> plain-text files rather than a database back-end, and integrates not only=
 with
> git but mercurial (and darcs).
>
> Gitit also incorporates the Pandoc<http://johnmacfarlane.net/pandoc/>  pr=
oject
> for its markup syntax, therefore enabling not only markdown but reST as a=
 master
> source input format, while DokuWiki has its own (yet another unique) mark=
up
> syntax 8-(
>
> With the increasing likelihood that I'll be using Leo as the centerpiece =
of my
> toolchain, plus the fact that Pandoc is much more actively maintained, it=
's
> starting to look worth my while to consider switching my "master source" =
content
> syntax over from Txt2tags to reST. The only downsides are that Gitit is a
> Haskell project rather than Python, and one thing I like about Txt2tags i=
s its
> support for conversion to AsciiDoc, rather than Pandoc's direct output to
> full-blown DocBook XML - but apparently even that's in the works in Pando=
c's dev
> version.
>
> Anyone in the Leo community using Gitit, especially for use beyond simple=
 code
> documentation?

Now that I'm using Leo + Fossil for my documentation related matters=20
and distributed work I certainly think that a distributed off-line=20
collaboration system for documentation is needed and, if MoinMoin can't=20
support the use of distributed wikis (and seems is not planned or in=20
development [1][2]) Gitit would be a nice place to start with this idea=20
and would offer advantages over the non-distributed and outdated Zope's=20
actual implementation, so, interested ones in the community could offer=20
an implementation of Gitit. On a related matter one of the problems I=20
see with actual server technology is its gigantism which concentrates=20
power in the people who has the resources, knowledge and time to=20
possess, understand and administer/intervene this technology so a=20
Global South Test for me about which server technology to choose is:=20
"it runs from a USB thumb drive?". This, for example, favors=20
Web2py/Smalltalk instead of Zope and Fossil instead of GitHub. May be=20
you should put this in the panorama when you judge GitIt or=20
Haskell/Pandoc. Pandoc, by the way, was for me a compelling reason to=20
learn Haskell[3] (but I thought that I would learn Smalltalk before)=20
because it deals elegantly with a problem in the diversity of markup=20
languages (txt2tags makes something similar but only in one way=20
translation) and for me the point of using Leo is having a tool to deal=20
consistently with diversity in the "sub-optimal distopic world of=20
everything is a file".

[1] http://moinmo.in/PawelPacana/MercurialBackend
[2] http://moinmo.in/MoinMoin2.0
[3] http://learnyouahaskell.com/

We could get philosophical here, and think about different programming=20
paradigms and languages that implement them with elegant syntaxes, like=20
Smalltalk, Haskell and Python versus the non elegant ones of .java, php=20
or ... (put your hated language here) and how this elegant syntaxes,=20
languages and computer using experience could cross-pollinate. If that=20
is the case, may be reading some about Combined Object Lambda=20
Architecture[4] and the comprehensive "Concepts, Techniques, and Models=20
of Computer Programming" by Van Roy and Haridi would be a nice reading.=20
Some times I dream of a world connected diversity where all the=20
problems of computer interaction can be solved by expressing that=20
diversity in fundamental constructs that respect it at the same time=20
that bring consistency and interface solving the apparent chaos and=20
noise.

[4] https://en.wikipedia.org/wiki/COLA_%28software_architecture%29

Cheers,

Offray

.. @+node:ekr.20130806072439.21305: *5* Re: Leo doc-generation and Wiki integration - GitIt and Pandocs
From: Matt Wilkie <maphew@gmail.com>

> Wow I think that this is the first time I have the opportunity to
> write (curiously in English instead of my native tongue) about
> that dystopy, because most of the time I just talk about this
> with my students or friends but not as detailed and contextually,
> so thanks for bring this up Hans, and thanks everyone else
> here who is still reading :-)

I am reading, and enjoying. The clouds you've placed in my mind are
making interesting shapes and I am intrigued. ;-)
.. @+node:ekr.20130806072439.21306: *5* Re: Leo doc-generation and Wiki integration - GitIt and Pandocs
From: =?UTF-8?B?T2ZmcmF5IFZsYWRpbWlyIEx1bmEgQ8OhcmRlbmFz?= <offray@riseup.net>

Hi,

El lun 23 ene 2012 01:18:48 COT, HansBKK escribi=F3:
> Thanks Offray for your detailed and informative response.

Well I'm enjoying also these talks with you. I think that putting=20
documentation also in the center is required if we want to break the=20
Leo's self-fulfilled prophesy about being a "ghetto tool" for=20
programmers only and I want this in the best way.

[..]
>
> I for some reason missed the MoinMoin's "simple page storage" option - th=
anks so
> much for pointing that out. For all the reasons you cite, and most import=
antly
> is much more mainstream, more actively developed and well-supported than =
Gitit,
> I'll definitely give it a higher priority in my testing.
[...]

I enjoyed using MoinMoin for this project:

http://el-directorio.org/

but at the end we could not intervene MoinMoin as much as we would like=20
because of the server permissions, that why I started to look more=20
integrated solutions of the development and deployment environment as=20
web2py or seaside, but they're not wiki engines properly but web=20
application frameworks (where you could build a wiki-engine if needed).=20
But surely

>      the "sub-optimal distopic world of everything is a file".
>
>
> I personally disagree with your dislike for "everything is a file" - I se=
e that
> principle as a fundamental part of the *nix tool philosophy, and IMO this=
 is a
> perfect example:
>
>      I certainly think that a distributed off-line collaboration system f=
or
>      documentation is needed and, if MoinMoin can't
>
>      support the use of distributed wikis (and seems is not planned or in=
 development
>
> To my mind, any wiki platform that can store the page data as plain text =
(as
> opposed to binary/database), in a format suitable for diff tools ("light"=
 markup
> as opposed to html/xml) can make use of whatever VCS for distribution/rep=
lication.

You're right and I like the idea of "everything is a something" when=20
that something is powerful unifying idea. That's the case with Unix's=20
"everything is a file" or Smalltalk's "everything is an object" (in=20
Unix you have also every tool makes one thing and makes it right,=20
combined with pipes). For me these two paradigm's were the ones that,=20
in 70's, were fighting for the mind share  about computer experience of=20
today and both of them won in a dystopic way, but for me "taking genius=20
to understand Unix simplicity"[0], was even more dystopic. When you're=20
trying to empower users the impedance between development and=20
deployment shows the dystopia, at least compared with the original=20
visions, so most of the "end users" cant change the tool that changes=20
them, so, someone else is making decisions about that changes and that=20
users.

[0] https://en.wikipedia.org/wiki/Unix_philosophy#Quotes

I like the simplicity of light markups and I try myself of not using=20
explicitly nothing as xml and I like also the idea of the light markup=20
being used by VCS tools. That's not where dystopia lies. The problem is=20
not about files or structure but about "meta-structure" (structure=20
talking about structure, as in meta-languages), specially=20
self-referential meta-structure, because self-referential=20
meta-structures are the key for self-directed change, as opposed with=20
change directed by others. When you see how the "world of everything is=20
a file" talks about itself, there is a lot of impedance and=20
discontinuity between source code, binary, apps and docs and there is a=20
long path for the user who is confined to using apps to create docs,=20
but never change the apps that could let she/he to change his/her=20
writing and that's why I want to use Leo this semester with=20
non-technical writers to explore the way that writing change the tool=20
that writes and not only the human who does.

For me a unified emergent meta-structure in the world of "everything is=20
a file" is where lies the power of Leo. You can use an outline to=20
change the way that Leo behaves and that's why having the Leo's=20
self-referential meta-structure is more powerful that the "dystopic=20
world of everything is a file" (in that world you don't have=20
meta-structure, only structure, mostly for storage purposes and the=20
intelligence to read/process it is mostly outside the file, in the=20
human reader, the compiler or the binary). What Leo does is to create=20
self-referentiality in the world of everything is a file by introducing=20
outlines that can talk/structure the files and that can talk about=20
outlines, i.e outlines that can talk about files and about themselves=20
and can reprogram the way Leo itself works, and so Leo is bridging the=20
gap between objects and files in a valuable and unique way.  But we=20
need still to improve, specifically we need a more elegant way to talk=20
about that files, specially about their changes in time, because is in=20
that change where talking with the distopic world has more problems and=20
possibilities, and that way I'm making the Fossil/VCS experiment and=20
also.

Wow I think that this is the first time I have the opportunity to write=20
(curiously in English instead of my native tongue) about that dystopy,=20
because most of the time I just talk about this with my students or=20
friends but not as detailed and contextually, so thanks for bring this=20
up Hans, and thanks everyone else here who is still reading :-)

>      On a related matter one of the problems I see with actual server tec=
hnology
>      is its gigantism which concentrates
>      power in the people who has the resources, knowledge and time to pos=
sess,
>      understand and administer/intervene this technology so a Global Sout=
h Test
>      for me about which server technology to choose is: "it runs from a U=
SB thumb
>      drive?".
>
> IMO "server" is a function, not a question of scale or complexity - the b=
etter
> question for my workflow is "does the app run portably?". I personally fi=
nd
> actually running stuff from flash drives too slow and data-dangerous.

I'm agree with you. Server and gigantism have not to be equal, but=20
unfortunately in the "dystopic informatic world" (where the previous=20
dystopia is just a part) they're most of the time. Portability is the=20
key, not flash drives. In my context they're just a medium to ask the=20
same as you, but also a way to let people take the technology with=20
them, no matter if they have access to a "classical" server.

>
> So far I've found that anything that runs under Linux is inherently porta=
ble in
> that sense.

Agreed. Having Leo + Fossil + Laptop ( ;-P ) gives me some kind of=20
portability, but we need more. That's why I think that we need a self=20
contained version of Leo with a default discourse about file flat world=20
change in time (at least for Windows), but ideally would be nice to=20
have something like the self-contained multiplatform Pharo's One Click=20
Experience[1]

[1] http://www.pharo-project.org/pharo-download

>      This, for example, favors Web2py/Smalltalk instead of Zope and Fossi=
l
>      instead of GitHub.
>
> I haven't any experience with these others, but note that Git does not =
=3D GitHub.
> I share your dislike for server/storage platforms out of my direct contro=
l, not
> least for privacy/security issues for many use cases. If I used Git for d=
ata
> distribution I wouldn't use GitHub, and my understanding is that even "Gi=
t for
> Windows" is already fully portable.

Oohh I don't make myself clear, sorry. Fossil compared with GitHub was=20
not because of the equivalence of Git and GitHub, but because of the=20
integration of web characteristics of GitHub in Fossil (wiki, tickets,=20
web interface and so on).

> For myself, I think mercurial would be a good fit, but my main point is t=
hat any
> moves toward a "distributed Leo" should IMO be VCS-agnostic, just as my p=
lans
> for enabling community editing of Leo-managed content will be wiki-platfo=
rm
> agnostic.

I fully share your opinion on that subjects, but in this case I want to=20
start by some specific implementation from which one start to abstract=20
that to think abstractly without any particular implementation in the=20
road, which is not your case, I just point to different implementation=20
strategies based on the same agnosticism/diversity as a valuable thing=20
to preserve.

> To me, the key enabler for that is "everything as a file". . .

For me the enabler is self-referential meta-structure

Thanks,

Offray

.. @+node:ekr.20130806072439.21307: *5* Re: Leo doc-generation and Wiki integration - GitIt and Pandocs
From: HansBKK <hansbkk@gmail.com>



Content-Transfer-Encoding: quoted-printable

On Monday, January 23, 2012 7:22:21 PM UTC+7, Offray Vladimir Luna C=E1rden=
as=20
wrote:
>
>
> documentation also in the center is required if we want to break the Leo'=
s=20
> self-fulfilled prophesy about being a "ghetto tool" for programmers only


Usability for clueless noobs is a lot of work, probably harder than the=20
complex whiz-bang functionality part.

And to take something as powerful and flexible as Leo and make it=20
accessible for noobs would require "lobotomizing" it to some extent, at=20
least hiding those features that weren't relevant to the intended=20
more-mainstream task at hand.

I imagine something like "application mode" flag at launch time=20
  - Leo as a journaling tool (like Rednotebook on steroids)
  - Leo as an Evernote-style note-taking brain extension
    - with user-accessible tagging, perhaps multiple headings per node?
  - Leo as a delicous-replacement (import/export/backup) bookmarks=20
management tool
  - Leo as a single-source multiple-output documentation management=20
meta-organizer and conversion-supporting tool

etc - very different UX - pane layouts, menu structures etc - for each=20
mode, but the same underlying code and data structures

but at the end we could not intervene MoinMoin as much as we would like=20
> because of the server permissions


ACLs is one of DokuWiki's strengths, as they target the corporate world (as=
=20
much as a FOSS tool can 8-)

> So far I've found that anything that runs under Linux is inherently=20
> portable in
>
> > that sense.
>
> Agreed. Having Leo + Fossil + Laptop ( ;-P ) gives me some kind of=20
> portability, but we need more.
>
Pocket-size portable HDD with USB2 / SATA2  (will soon start converting to=
=20
v3 of both, used to use Firewire), booted up using any arbitrary internet=
=20
cafe / friend / customer desktop.

ideally would be nice to have something like the self-contained=20
> multiplatform Pharo's One Click=20
> Experience[1]
>
> [1] http://www.pharo-project.org/pharo-download
>
Most of the mainstream distros now have easy-to-customize=20
create-your-own-distro LiveCD/USB+persistent storage projects. I've got a=
=20
portable drive that launches a GRUB2 boot menu letting me choose between=20
various configs of Fedora, Red Hat, Debian, Ubuntu and Slax, all of which=
=20
access shared /home and server-data partitions (which gets sync'd with my=
=20
central filer). Check out Sardu <http://www.sarducd.it/>, which also=20
handles all the mainstream recovery/rescue/sysadmin tools like grml,=20
pmagic, sysresccd - even BartPE, Win7 repair etc all on the same pocket=20
drive. . .
=20

> integration of web characteristics of GitHub in Fossil (wiki, tickets, we=
b=20
> interface and so on).
>
=20

> agnosticism/diversity as a valuable thing to preserve.

=20
Personally I prefer using CLI batch/scripts and/or TortoiseXX rather than a=
=20
web interface for my VCS usage, and my ticket/project management/GTD system=
=20
of choice is Redmine (likely Chili soon).=20

Both of these integrate well with the important VCSs, so when I finally get=
=20
away from SVN and get familiar with the distributed new kids, I can keep my=
=20
other tools - Redmine/Chili now has such a custom-infrastructure encrusted=
=20
around it sync'ing with gcal, printing pocketmods for my calendar and=20
@context to-do's that have become indispensable to my day-to-day life=20
management.

=20

> "dystopic world of everything is a file" (in that world you don't have=20
> meta-structure, only structure, mostly for storage purposes and the=20
> intelligence to read/process it is mostly outside the file, in the human=
=20
> reader, the compiler or the binary). What Leo does is to create=20
> self-referentiality in the world of everything is a file by introducing=
=20
> outlines that can talk/structure the files and that can talk about=20
> outlines, i.e outlines that can talk about files and about themselves=20
> and can reprogram the way Leo itself works, and so Leo is bridging the ga=
p=20
> between objects and files in a valuable and unique way.  But we need stil=
l=20
> to improve, specifically we need a more elegant way to talk about that=20
> files, specially about their changes in time, because is in that change=
=20
> where talking with the distopic world has more problems and=20
> possibilities, and that way I'm making the Fossil/VCS experiment and also=
.
>

> To me, the key enabler for that is "everything as a file". . .
>
> For me the enabler is self-referential meta-structure
>
=20
I don't see any conflict between the two, IOW no inherent limitations to=20
"everything is a file" other than (to me, at least within the personal-use=
=20
prototyping context) unimportant factors like relative speed/scaleability -=
=20
it's "just" an implementation detail.=20

The various levels of structural overlays as presented within Leo as=20
"uber-manager of the metadata" can be as flexible and complex as can be,=20
and still be stored/distributed as diffed/versionable/convertable files at=
=20
whatever appropriate level of granularity to support integration with=20
outside toolchains. To the extent design choices are made that "lock in" to=
=20
a particular "higher level" technology bet, e.g. a specific database engine=
=20
or DVCS, then much higher-level programming/sysadmin skills are required in=
=20
order to integrate Leo into the thousands of mainstream tools that have=20
evolved over time to support structured-plain-text.

Look at source code - after all these decades, it's still stored as plain=
=20
text in a filesystem. There's a reason for that - any language that=20
required its modules/functions/objects whatever to be stored in a=20
"proprietary" database engine for example would have very limited uptake,=
=20
because coders would have to put so much effort into infrastructure=20
overhead work to be able to keep working with their preferred toolset.=20
Anyway 'nuff said on that.

.. @+node:ekr.20130806072439.21308: *5* Re: Leo doc-generation and Wiki integration - GitIt and Pandocs
From: Largo84 <Largo84@gmail.com>

This topic is of much interest to me as I use Leo primarily for writing 
documentation (mostly LaTex, some html and some rST). I haven't worked w/ 
Pandoc yet but am interested in some of the possibilities. Thanks for the 
links, I'll check them out.
.. @+node:ekr.20130806072439.21309: *5* Re: Leo doc-generation and Wiki integration - GitIt and Pandocs
From: HansBKK <hansbkk@gmail.com>



Content-Transfer-Encoding: quoted-printable

Thanks Offray for your detailed and informative response.

On Friday, January 20, 2012 5:34:21 PM UTC+7, Offray Vladimir Luna C=E1rden=
as=20
wrote:
>
> When you suggested DocuWiki I thought of MoinMoin which has also support=
=20
> of plain files as storage mechanism but is also scalable to databases if=
=20
> this is needed and it supports reStructuredText and is made in python, a=
=20
> language that "leonizens" are familiar with.
>
 I for some reason missed the MoinMoin's "simple page storage" option -=20
thanks so much for pointing that out. For all the reasons you cite, and=20
most importantly is much more mainstream, more actively developed and=20
well-supported than Gitit, I'll definitely give it a higher priority in my=
=20
testing.

=20

> the "sub-optimal distopic world of everything is a file".
>
 =20
I personally disagree with your dislike for "everything is a file" - I see=
=20
that principle as a fundamental part of the *nix tool philosophy, and IMO=
=20
this is a perfect example:

 I certainly think that a distributed off-line collaboration system for=20
> documentation is needed and, if MoinMoin can't=20
>
> support the use of distributed wikis (and seems is not planned or in=20
> development
>
To my mind, any wiki platform that can store the page data as plain text=20
(as opposed to binary/database), in a format suitable for diff tools=20
("light" markup as opposed to html/xml) can make use of whatever VCS for=20
distribution/replication.

=20

> On a related matter one of the problems I see with actual server=20
> technology is its gigantism which concentrates=20
> power in the people who has the resources, knowledge and time to possess,=
=20
> understand and administer/intervene this technology so a Global South Tes=
t=20
> for me about which server technology to choose is: "it runs from a USB=20
> thumb drive?".
>
IMO "server" is a function, not a question of scale or complexity - the=20
better question for my workflow is "does the app run portably?". I=20
personally find actually running stuff from flash drives too slow and=20
data-dangerous.

In my workflow, at the beginning of a session I first sync the relevant=20
data and "portable apps" filesystem branches, then run everything off the=
=20
local HD. At the end of a session I sync it all back - most of the time=20
these days this is to/from a central filer, but I do have portable drives I=
=20
use for this when that's required or more convenient, which then get sync'd=
=20
to the filer next chance I get.

So far I've found that anything that runs under Linux is inherently=20
portable in that sense.
=20

> This, for example, favors Web2py/Smalltalk instead of Zope and Fossil=20
> instead of GitHub.
>
I haven't any experience with these others, but note that Git does not =3D=
=20
GitHub. I share your dislike for server/storage platforms out of my direct=
=20
control, not least for privacy/security issues for many use cases. If I=20
used Git for data distribution I wouldn't use GitHub, and my understanding=
=20
is that even "Git for Windows" is already fully portable.

For myself, I think mercurial would be a good fit, but my main point is=20
that any moves toward a "distributed Leo" should IMO be VCS-agnostic, just=
=20
as my plans for enabling community editing of Leo-managed content will be=
=20
wiki-platform agnostic.

To me, the key enabler for that is "everything as a file". . .
.. @+node:ekr.20130806072439.21323: *4* Leo reader as a web app
From: "Ville M. Vainio" <vivainio@gmail.com>

I want to do some technology evaluation, so I will start doing a Leo
file reader for mobile devices using:

- jQuery mobile
- CoffeeScript

This can be deployed on web or locally. Interesting use cases are
browsing Leo notes you composed elsewhere on your tablet, and
publishing leo docs on the web (e.g. we could host fully browseable
leo source outline on Leo website)

I will notify the mailing list on the progress; it may be slow since I
don't have much contiguous time slots for hobby projects at the
moment. If someone wants to hop along, all the better; I'll probably
start the project at github once I have something that runs on a
desktop browser properly.

===== <offray@riseup.net>

Me and some friends where just thinking (but still I can not express my 
thoughts in code) in having something like and Etherpad[1] + Leo real 
time outliner and document creator. And I thought that would be nice to 
learn web2py in order to create the app and may be have jstree[2] or 
dynatree[3][4] as a way to create the heads of the nodes and put them in 
the web. Every node would be an etherpad-lite document ready for 
collaboration. At this point I have only links and no development now or 
in the coming times, but may be this can be helpful for your project.

[1] http://etherpad.org/
[2] http://dev.s-cubism.com/plugin_jstree
[3] https://code.google.com/p/dynatree/
[4] http://wwwendt.de/tech/dynatree/doc/samples.html

By the way I have been using txt2tags again for writing real-time 
structured docs with my students using etherpads and is really easy. Now 
I have found a txt2tags multiplataform editor at:

http://nestededitor.sourceforge.net/about.html

may that project be of some inspiration,
.. @+node:ekr.20130806072439.21332: *4* Leo tags *
From: Terry Brown <terry_n_brown@yahoo.com>

Does leo need tags for nodes?

===== Kent

Yes. My view of Leo as a data manager means I want tags. I've been thinking
I'd address them in the context of the db of nodes, all the better if they
were native.

===== EKR

A very quick first response.

- Support for tags as uA's would be natural.
- User interface issues more complicated, of course.
- In general, Leo has not paid enough attention to searches/tags as alternatives to clones.
- Finding by tag, cloning by tag, etc. all seem natural.
- Kent's and Terry's suggestions are always worth consideration :-)

===== Jacob Peck <gatesphere@gmail.com>

I sort of implemented tags in my rpg.leo project - basically a series of
buttons that interacted with the nav pane to search for hashtags, which
were simply part of headlines.

It worked, it was simple, and to be honest, I don't think that Leo really
needs them. I'm sure there is some functionality that I'm missing out on,
though. Perhaps for those who don't wish to maintain lists of clones, or
for sorting into groups based on common tags. Perhaps even a view-rendered
extension that would render a clickable tag cloud of an entire outline?

===== Terry

Interface wise I see something similar to the the bookmarks.py
interface, shown in the attached, colored strings indicating the tags a
node has, probably a bit smaller.  Various commands and clicks for
adding or removing tags and navigating through the nodes with a
particular tag, or set of tags.

===== Kent

Display location, maybe a tab in the output pane.
Maybe enter them via minibuffer?
<alt-x> tags= ideas, terry, tagging

Maybe they could display in the minibuffer until <alt-x> was pressed. IE;
tags for current node on display until minibuffer is needed.

===== Terry

This would be useful for all sorts of things, but Leo, being Leo,
already has features that overlap functionality wise.  You could
collect clones of all the nodes you want to identify with a particular
tag, under a single parent node, which becomes the tag proxy thing.

You can do something similar with the backlinks.py plugin which provides
unrestricted node linking, just link all the nodes which need a
particular tag to a particular node.

But I'm guessing only a tag centric UI component will give the quick
and easy use you'd want from a tagging system.  Data wise I guess tags
could be a simple list of string, p.v.u['_tags'], with Leo maintaining
an index of tag to node list mappings.

===== Kent

wish list:
- tab completion / drop-down list to prevent creating similar tags
- import / export of tags, encourage consistent ontologies
- hooks which parse the node content, create tags from them
.. @+node:ekr.20130806072439.21341: *4* Node pipes
From: Kent Tenney <ktenney@gmail.com>

The editor envy resulting from the Light Table demo has me revisiting
a feature that's been percolating.

Sending output to the log pane is very useful, it's how Leo talks back.

Executing from the command line means one space for input and output.

Executing in a Leo node and writing to the log improves on this by providing
different spaces for input and output.

Could Leo generalize this concept such that any node could be designated as
a destination for output?

Given multiple visible nodes, akin to Terry's stickynotes, or Ville's
recent grid
suggestion, Leo could duplicate the power of simultaneous feedback shown
by Light Table.

I guess 'rendering' addresses this to some degree.

Reminds me of the power graph database folks talk about, where you can
define nodes and edges to be whatever you want.

The nodes could be sources or sinks.
Sources: code or commands ...
Sinks: standard out, tail -f logfile, network traffic, introspection ...

The edges would define handlers for the content of the sources, format the
results and send to the sinks.

So, as I write code in one node, I can see a node displaying stdout, another
watching a log file, another showing docstrings, another showing test
results ...

===== Ville

The 'ileo workbook' concept is relevant; it allowed you to easily reference
other nodes in your scripts (wb.foo meant node with headline 'foo').

It's nice in theory, but the rigid ui model where we show only one node at
a time made it hard to visualize. Tabula or grid would make it more
concrete and intuitive - you could show input, output and the manipulator
script at the same time. Or make small nodes with intermedote results etc.

How this would relate to 'pipeline' - you would have explicit way to say
what nodes are input, whan nodes are output and what are the scripts that
transform input to output. Editing inputs or scriyts would ping you somehow
that outputs are out of date, allowing you to easily press button to
recalculate outputs.
.. @+node:ekr.20130806072439.21342: *5* Re: Node pipes
From: "Edward K. Ream" <edreamleo@gmail.com>

On Wed, Apr 18, 2012 at 9:48 AM, Kent Tenney <ktenney@gmail.com> wrote:

> Could...any node...be designated as a destination for output?

Certainly.  Just assign to v.b in the appropriate place.

> could [Leo] duplicate the power of simultaneous feedback shown by Light Table.

Yes, provided somebody understands what the simultaneous feedback is ;-)

Tabula might be natural for that, perhaps enhanced via free_layout.

> I guess 'rendering' addresses this to some degree.

Interesting connection.  We might want to render to tabula nodes.

> Reminds me of the power graph database folks talk about, where you can
> define nodes and edges to be whatever you want.

This is coming.  Redefining edges would be easy provided that they had
different colors from the "main" edges.

> The nodes could be sources or sinks.
> Sources: code or commands ...
> Sinks: standard out, tail -f logfile, network traffic, introspection ...

Yes.  This is a straightforward generalization of your first question.

> The edges would define handlers for the content of the sources, format the
> results and send to the sinks.

A new idea!  This could be revolutionary!

> So, as I write code in one node, I can see a node displaying stdout, another
> watching a log file, another showing docstrings, another showing test
> results ...

To paraphrase: nodes and links are not simply ways to represent
structure.  They may have independent identity and function.  A
brilliant idea.

Edward
.. @+node:ekr.20130806072439.21344: *5* Re: Node pipes
From: "Edward K. Ream" <edreamleo@gmail.com>

On Wed, Apr 18, 2012 at 11:47 AM, Kent Tenney <ktenney@gmail.com> wrote:

>> Certainly. Just assign to v.b in the appropriate place.
>
> Right. Leo can be considered a programming language, it is able
> to do most anything one dreams up. Here we are discussing what
> features are appropriate to add to the 'standard library' IE: put the
> effort into making the capability an API call instead of a bunch of code.

In fact, the inadequacy of my remark that assigning to v.b was all
that was needed lead me to consider the broadcaster/listener
framework.

The idea is that the v.b setter property would broadcast the fact that
v.b has changed to all the listeners connected to v.  Presumably,
those listeners will be UI elements that will update their text from
v.b and recolor as appropriate.

We might generalize this concept to update outline structure in those
UI elements that show outlines.

> My impression of the Light Table demo is that the right side of the scree=
n was reporting interesting information about what was being typed on the l=
eft side. Seems like it could be called "simultaneous feedback"

An excellent generalization.  We can use this without knowing exactly
what the feedback is, or where it comes from.

> I'm unable to keep up, unaware of the capability of free_layout,
> tabula, rendering, but I expect most if not all of the tools are availabl=
e.

Keeping up with ourselves these days seems like a full-time job.

I believe a broadcaster/listener event framework is an essential
ingredient.  It shouldn't be too hard to do, it will simplify existing
code, and it will be an enabling technology that will stimulate
further development.
.. @+node:ekr.20130806072439.21349: *4* OMG: @nosent should put headlines as comments
From: "Edward K. Ream" <edreamleo@gmail.com>

I've been blind all these years!  @nosent should put headlines as nodes a 
comments.  They would be very useful and I can see no reason not to put 
such comments.  If, for some reason, they are not desired, you could use 
@asis.

===== Ville

I use @nosent for non-code text mostly, and it's not clear what "comment"
should mean in that context.

I for sure would like this kind of feature, but sometimes I'd like to have
the headlines written as reST style headlines (underlines), etc.

So this is not a complete no-brainer modification.

===== EKR

I agree.  Some more thought is needed.

===== Ville

Instead of changing how Leo fundamentally behaves (@nosent is part of
that), how about adding a new @directive that allows things like this? E.g.
"@write a.txt" would be nice & "obvious".

===== EKR

In this case, adding support for a new directive might be more complicated
than changing @nosent :-)


.. @+node:ekr.20130806072439.21370: *4* Parameterized template nodes
From: Alexandre_Toledo?= <jalexandretoledo@gmail.com>

As I use Leo to write PL/SQL code, I need to write similar text several
times, changing only small parts of it. It would be great if I could create
a node with the "template" and then clone it everywhere it should be
written, and then providing the parameters to be used in this writing.

Let me try to clarify it. I'd like to create a tree like this:

 +- @file something.sql
           +- Section 1
              + << Clone >> with Parameters A, B
           +- Section 2
              + << Clone >> with Parameters C, D

In this tree, both "Clone" nodes would be generated from a template
specified somewhere in the tree, and would have parts of its text replaced
with values "A" and "B" in Section 1, and "C" and "D" in Section 2.

I've searched but couldn't find anything like this, then I've thought of
trying to write a hook to intercept the "save" command, but couldn't think
of a way to pass the parameters; I think the obvious way would be to put
the parameters after the "<< >>", but then all cloned nodes are changed, so
it wouldn't work.

Another alternative would be creating some kind of directive @something,
but I have no idea of how to do that.

Any ideas?

===== EKR

Variants of this seem to be wanted by many people.  Most recently, there is
the thread, "Templates with macro expansions",
https://groups.google.com/forum/?fromgroups=3D#!topic/leo-editor/nF2lUEUtaUE

Does that do what you want?
.. @+node:ekr.20130806072439.21371: *5* Re: Parameterized template nodes
@nocolor

From: <fidelperez@gmail.com>

I know a programming IDE
<http://sourceforge.net/projects/doublesvsoop/>which bases its existence in
that concept:

You write "code Masks" and whenever you call a piece of code it will ask
only for the parameters, and write the rest of the code. There are already
some languages with most of the masks (all the primary functions and some
complex ones) and its growing.

For instance, if you write:

"window" it will add the window to the code and let you edit the params.

Their functionality would be awesome in Leo and when I know a bit better I
will try to emulate on it. Sticking to Leo tho since it has a much superior
way of managing data.
.. @+node:ekr.20130806072439.21372: *5* Re: Parameterized template nodes
@nocolor

From: Terry Brown <terry_n_brown@yahoo.com>

On Sun, 5 May 2013 16:35:59 -0700 (PDT) <fidelperez@gmail.com> wrote:

> I know a programming IDE <http://sourceforge.net/projects/doublesvsoop/>which bases its existence in that concept:
>
> You write "code Masks" and whenever you call a piece of code it will ask
> only for the parameters, and write the rest of the code. There are already
> some languages with most of the masks (all the primary functions and some
> complex ones) and its growing.

I suspect different people have different things in mind when they talk
about templates.

Leo's abbreviation system is already quite advanced when it comes to
filling in skeletons of common code layouts.  I type

  def;;

and I get

  def foo(this, that=3D3):
      """foo - Return
 
      :Parameters:
      - `this`: <|describe this|>
      - `that`: <|describe that|>
      """
 
      <|code|>

Two "parameters" are interactively requested, the function name, and
the list of arguments.  The node name is presented as the default for
the function name, and 'self' is included in the list of arguments, so,
assuming the node was already called 'foo', all I type is this, that=3D3.
The layout above is the rst form of the epydoc/sphinx docstring with
formally identified parameters.

The cursor is positioned after Return, where the was an empty <||>
placeholder.  Pressing ,, selects the next placeholder so that typing
replaces it.

There's more, see
https://groups.google.com/forum/?fromgroups=3D#!topic/leo-editor/5ni2PwfmBz8
and the screencast linked from there
http://www.greygreen.org/tmp/leoabbrev.ogv

Other people, Jacob etc. I think, have been talking about templates
where the input parameters are stored in the outline, allowing for
some of them to be altered and the template generation step re-run.
More like generating a website from data etc.
.. @+node:ekr.20130806072439.21375: *5* Re: Parameterized template nodes
@nocolor

From: <jalexandretoledo@gmail.com>

I've tried it and it's great, I think it will be useful, but it's not what
I was thinking of...

Let me try to explain what I had tougth about... What I would like to do is:

 1. create a new .leo file
 2. add a "template" node (eventually with sub nodes) with some ${schema}
and ${table} macro place holders in its contents
 3. add a @file node to the .leo file
 4. add to this @file node a new one with definitions such as
schema=3DSCHEMA_NAME and table=3DTABLE_NAME
 5. add as a sub node to this last one a clone from the "template" node;
 6. then, when I save everything, the @file would have "SCHEMA_NAME" and
"TABLE_NAME" everywhere a "${schema}" or a "${table}" were in the original
template node.

It would be important that, when I reopen the .leo file later, the macros
in the @file node where shown as ${schema} and ${table}, and not as it's
substituted text.

Now that I've described it, I can't see how it would be done... The
${macro} place holders should be on the contents of the @file node, so
after substitution, how could we recover it?

That's also why the code from Jacob is not what I need (but I'm already
thinking of other uses for it :) ): it will create a text when the button
is pressed, but the generated nodes will be just static text.
.. @+node:ekr.20130806072439.21380: *4* QML - new window / gui / coding for Leo?
From: Terry Brown <terry_n_brown@yahoo.com>

This thread will need Ville to set it on the right track, I barely know
the names of the technologies, but Qt has been advancing with, quoting
from their site:

Qt Quick

The Qt UI Creation Kit lets you create rich, touch-enabled UIs and
apps...quickly.

  * QML - CSS & JavaScript like language, same code base for UI
    designers & developers

  * Supported by Qt Creator IDE for rapid prototyping and development

  * Qt Quick UI runtime - Direct access to native APIs, performance
    boost with C++

I think the first bullet is most relevant to Leo.  Could we embed this
kind of environment in Leo?  Can it be integrated effectively with the
current GUI?

That route might make adding task specific GUIs in Leo quick and easy.

Not for the touch part (although Leo on a tablet would be fun), but as
a way of quickly creating task specific GUIs, "forms" if you like, for
accessing / interacting with the data in a Leo outline.  I'm assuming
that QML is higher level / less coding the regular PyQt programming,
but I don't know that, not having tried it.

===== Ville

QML is actually lower level than QWidgets / "regular" PyQt
programming. Key selling point of QML is that the UI's are more free
form, "custom" and much faster than QWidget UI's (in Qt5, QML maps
quite naturally to OpenGL, making it fly on mobile phone/tablet
hardware).

QML would be natural for graphcanvas / tabula / other "custom" ui
plugins, but it doesn't yet have text editor as powerful as QTextEdit,
not tree widget as powerful as QTreeWidget / QTreeView.

I expect QML to be first used in mobile version of Leo (I have one
actually, that I will publish "at later date" ;-). For desktop, QML is
not yet as attractive as the "old stuff".


.. @+node:ekr.20130806072439.21428: *4* Set of markup2html converter
From: tfer <tfetherston@aol.com>

Having played with Jacob Peck's markdown fork, I now get what leo is doing 
to provide a preview of text using a markup type. It is converting that 
markup, (rst: built-in, markdown: proposed).  What is being done is to run 
the text through a xxx2html converter and then using a Qt window widget 
that renders the generated html.

There have been requests to extend the built in rst functionality to other 
markup types, (Peck has an experimental one for markdown).  Rather than 
added them piecemeal, I think we could incorporate the code github uses to 
allow people to use their preferred markup language for their projects 
readme file.  Although a number of the converters are written in ruby, some 
are python and one is even pearl.  It is an extensible scheme.  The license 
for the library is basically, "keep the copyright notice and have at it", 
so it shouldn't cause any problem.

The code is here:
  https://github.com/github/markup

The current "see the selected node's body text" in the view-render-pane 
should work, the only thing lacking is a way to preview an entire file. 
 How about adding an option to preview it in the context menu for a right 
click on an @file node?

===== From: Jacob Peck <gatesphere@gmail.com>

That was actually my first thought when approaching the markdown 
implementation.  The major problem here is that the wrapper program, and 
several of the assorted converters are in ruby.  The only python one is 
rest2html, which we already have (via docutils).  I don't think adding 
ruby and perl as dependencies for one small feature of Leo would be 
wise...  that seems to me to be the very definition of bloatware.

That being said, github-markup supports the following formats, which are 
supported by python libs:

markdown (markdown)
rst (docutils)
textile (textile)
org mode (pyorgmode)
creole (python-creole)
mediawiki (mw2html)
asciidoc (asciidoc)

The following do not have a python equivalent (to my knowledge):

rdoc (ruby documentation)
perlpod (perl documentation)

I could certainly keep hacking on viewrendered to support the first 
list, if interest is high.

> The current "see the selected node's body text" in the 
> view-render-pane should work, the only thing lacking is a way to 
> preview an entire file.  How about adding an option to preview it in 
> the context menu for a right click on an @file node?
I could look into this suggestion too, if someone would point me in the 
right direction with respect to 2 things (I'm really new to Leo, so I 
have no idea where these things are in the source):

1. How to add a context menu item for a node
2. How to get a "full file" without saving it, i.e., fill in the << 
references >>, @others, and @all directives.

.. @+node:ekr.20130806072439.21443: *4* threaded saveAll()
From: Terry Brown <terry_n_brown@yahoo.com>

I guess this is a wishlist item - I suspect it is a result of my
workflow that might be quite different from other peoples, but I often
need to save 4, 6, even more open changed Leo files at once.  Mainly
when I'm filing / adjusting todo items, although at the end of a
session having 4 changed files open can't be that unlikely.

So it would be really nice if c.saveAll() could be threaded.  Even as I
write this, it gets more complicated as I think about it :-}

  - each thread should do no user interface calls, or at least no calls
    that aren't deferred to the main thread

    - that's ok, would take quite a bit of tracing to catch them all,
      but doable - except - plugins called from save hooks might break
      the rule

  - updating recent files list would have to be done properly, not a
    big deal

  - multiple threads saving to the same external files would be a
    problem, that's the complication that only just occurred to me

I don't typically have the same external file referenced from multiple
Leo files, why would you do that... so the last problem, although
potentially major, might be theoretical more than practical.

Hmm, well it's a thought.  First thing to check, is saving IO bound or
CPU bound...
.. @+node:ekr.20130806072439.21444: *5* Re: threaded saveAll()
From: "Ville M. Vainio" <vivainio@gmail.com>

Since the flat document is a sort of "rambling" blue sky topic, I added
some more thought on G+ leo community instead of increasing mailing list
noise:

https://plus.google.com/103097156557482112329/posts/Vp5ansTdLwq
.. @+node:ekr.20130806072439.21445: *5* Re: threaded saveAll()
From: "Ville M. Vainio" <vivainio@gmail.com>

--f46d042fd84e36bae704d78bf5db


I'm pretty sure saving is cpu bound; for "normal" size documents, flushing
that kind of stuff to disk (or memory buffers that are to be written to
disk) shouldn't take significant amount of time.

.. @+node:ekr.20130806072439.21446: *5* Re: threaded saveAll()
From: Terry Brown <terry_n_brown@yahoo.com>

On Sat, 9 Mar 2013 14:46:09 -0600
Terry Brown <terry_n_brown@yahoo.com> wrote:

> I guess this is a wishlist item - I suspect it's a result of my
> workflow that might be quite different from other peoples, but I often
> need to save 4, 6, even more open changed Leo files at once.  Mainly
> when I'm filing / adjusting todo items, although at the end of a
> session having 4 changed files open can't be that unlikely.

I've just found that, because these todo items are always in the
outline itself and not external files, I can just do 
'write outline only' on all the open outlines, and this is much faster
and smooths out the bump in my workflow that got me started thinking
about this.
.. @+node:ekr.20130806072439.21447: *5* Re: threaded saveAll()
From: Terry Brown <terry_n_brown@yahoo.com>

On Sun, 10 Mar 2013 08:13:41 +0200
"Ville M. Vainio" <vivainio@gmail.com> wrote:

> I'm pretty sure saving is cpu bound; for "normal" size documents, flushing
> that kind of stuff to disk (or memory buffers that are to be written to
> disk) shouldn't take significant amount of time.

Probably right, so could you use `multiprocessing` instead of
`threading`?  More challenging implementation wise, but I'm wondering
if it's even possible, in terms of handing over the in-memory data
structure?
.. @+node:ekr.20130806072439.21448: *5* Re: threaded saveAll()
From: "Ville M. Vainio" <vivainio@gmail.com>

--14dae9340445ec94c604d796bde2


Multiprocessing based implementation will likely be quite hard, and once
you walk the trees anyway and copy the data over the process boundary, it
could cause bad pauses in execution.

I have often thought how nice it would be to have "flat" storage for the
leo document, so that you could just copy over a flat chunk of memory and
let other processes traverse that. Doing that is a somewhat nontrivial
undertaking, to say the least :).

I'd just start with threads, despite the GIL problems.
.. @+node:ekr.20130806072439.21298: *4* Treat leo tree as a flat memory structure
Ville
https://plus.google.com/_/notifications/emlink?emr=02870587547267324596&emid=CLiiydTt8rUCFaY6MQodYAsAAA&path=%2F103097156557482112329%2Fposts%2FVp5ansTdLwq&dt=1362942818945&ub=63

How could we  treat leo tree as flat, contiguous memory structure (something that's easy to memcpy, pass as shared memory or flush to disk in one write)?

Some ideas could be: 

- Use Redis to store tree
- Keep the "clean" body texts in contiguous block (most bodies will always be clean), append dirty (modified) body texts after it
- Keeping the outline structure in memory block is quite easy, since there is not a lot of data. You could have just a list of [parent, child] id's or whatever
.. @+node:ekr.20130806072439.21464: *4* UI idea: body editors in a grid
From: "Ville M. Vainio" <vivainio@gmail.com>

Hey,

No time to mock this up right now, just throwing it out there.

"tabula" plugin allowed you to edit many nodes simultaneously in an
MDI canvas - i.e. you could move the body editors around freely.

How about taking this idea further and locking the body editors in a
grid, or column?

One fun idea would by layout like this

            | Child 1
Outline  | Child 2
            | Child3

That is, you would edit and view all the children of the currently
focused node all at once. We can already do two body editors at once,
so this would seem like natural extension.

Of course you could only see a small amount of text per body, but for
a "workbook" / sheet like use cases it would be fine.
.. @+node:ekr.20130806072439.21465: *5* Re: UI idea: body editors in a grid
From: "Edward K. Ream" <edreamleo@gmail.com>

On Apr 18, 10:53=A0am, Terry Brown <terry_n_br...@yahoo.com> wrote:

> When the body editor is a well behaved widget it should be straight
> forward to place them where ever you want in using the free-layout
> mechanism.

Yes.  This might the key.

As I was thinking about doing body editors with free_layout (and by
extension, the tabula editors) I had another new thought: it's time to
replace the present difficult selection code with a broadcaster/
listener framework.

In particular, the multiple body editor code is on the verge of
collapse because it tries to figure out too much in a spaghetti-like
mass of logic.  This doesn't generalize, and Leo is becoming so
"exuberant" in its IDE that a simpler, more general mechanism is
becoming essential.

Edward

.. @+node:ekr.20130806072439.21466: *5* Re: UI idea: body editors in a grid
From: "Edward K. Ream" <edreamleo@gmail.com>

On Wed, Apr 18, 2012 at 4:37 AM, Ville M. Vainio <vivainio@gmail.com> wrote:

> "tabula" plugin allowed you to edit many nodes simultaneously in an
> MDI canvas - i.e. you could move the body editors around freely.

Tabula is part of the stickynotes plugin.  It creates the following commands:

         tabula
         tabula-marked
         tabula-show
         tabula-subtree

The "windowlets" show the node's headline. So this is the "sea of nodes" view!

The tabula nodes are "live": changes made in the tabula window
instantly affect the corresponding nodes in the regular outline.

An easter egg: double-clicking the title of a windowlet fills the
tabula window with the windowlet.  Another double-click undoes the
expansion.

> How about taking this idea further and locking the body editors in a
> grid, or column?

Good idea.  The tabula window is a great playground for invention.

In the "multi-colored link" world (coming soon, I hope), we could
imagine commands that create "tabula-colored" links, so that the
tabula window would work like a chapter.  (And each chapter would have
its own links).

The Light Table video suggested something else that I never considered
before.  Suppose each node "carries" its own mini-context outline,
showing just the parents of the node.  The tabula window might be
natural for that.

The idea is that each windowlet would have two parts:  the top would
show the parents, the bottom would show the body pane.  This allows
context to be visible without actually having to show the outline
pane.

Edward
.. @+node:ekr.20130806072439.21467: *5* Re: UI idea: body editors in a grid
From: "Edward K. Ream" <edreamleo@gmail.com>

On Wed, Apr 18, 2012 at 10:53 AM, Terry Brown <terry_n_brown@yahoo.com> wrote:
> On Wed, 18 Apr 2012 12:37:22 +0300

> When the body editor is a well behaved widget it should be straight
> forward to place them where ever you want in using the free-layout
> mechanism.

Are you suggesting doing free-layout in tabula?

EKR
.. @+node:ekr.20130806072439.21468: *5* Re: UI idea: body editors in a grid
From: "Ville M. Vainio" <vivainio@gmail.com>

--20cf3005df0ef84cc304be0227bb


If you fill the cells with stickynotes (as in tabula), the editors would at
least stick to the nodes.

Otoh, if more felxible body editors are just around the corner, it may not
be worth the hassle.

.. @+node:ekr.20130806072439.21469: *5* Re: UI idea: body editors in a grid
From: Kent Tenney <ktenney@gmail.com>

On Wed, Apr 18, 2012 at 2:57 PM, Edward K. Ream <edreamleo@gmail.com> wrote=
:
> On Apr 18, 10:53=A0am, Terry Brown <terry_n_br...@yahoo.com> wrote:
>
>> When the body editor is a well behaved widget it should be straight
>> forward to place them where ever you want in using the free-layout
>> mechanism.
>
> Yes. =A0This might the key.
>
> As I was thinking about doing body editors with free_layout (and by
> extension, the tabula editors) I had another new thought: it's time to
> replace the present difficult selection code with a broadcaster/
> listener framework.

'publish / subscribe' has buzzword cred these days, there are several
protocols out there, reportedly fairly simple to implement, don't know
if any are a fit here.
.. @+node:ekr.20130806072439.21470: *5* Re: UI idea: body editors in a grid
From: Terry Brown <terry_n_brown@yahoo.com>

--MP_/YLiyZOi3S=ZU5mZC9llHxW5

Content-Disposition: inline

On Wed, 18 Apr 2012 12:48:42 -0700
Ville Vainio <vivainio@gmail.com> wrote:

> > Expanding the scope to a grid, we could have a grid-lock-column that would
> > freeze the current column, allowing you to move the selected position in
> > the tree to another node, and locking the nodes for column 2 etc etc  

Attached screen-shot shows the potential for free-layout with the new
Open Window command to open a separate window as a 'grid' editor.  Here
instead of body editors I just have 5 view-rendered panes open, and
they're all looking at the same node because there's no mechanism for
locking them to separate nodes presently(*).  Free layout could handle
body editors in the same way, if they were more agnostic about their
containers.

Cheers -Terry

(*) I think there's a way to lock/unlock a special case singleton
view-rendered pane, but not a flock of them like this.
.. @+node:ekr.20130806072439.21471: *5* RE: UI idea: body editors in a grid
From: Ville Vainio <vivainio@gmail.com>

You are probably right. We Could also adjust the sizes dynamically
based on the amount of text in the nodes

Sent from my Windows Phone
From: Terry Brown
Sent: 4/18/2012 10:31 PM
To: leo-editor@googlegroups.com
Re: UI idea: body editors in a grid
On Wed, 18 Apr 2012 21:42:21 +0300
"Ville M. Vainio" <vivainio@gmail.com> wrote:

> I am bringing another angle into play here - systematic selection of what
> nodes are shown in the editors, in the proposed scheme we would have a
> single column of editors, each displaying every child of currently selected
> node.
>
> Expanding the scope to a grid, we could have a grid-lock-column that would
> freeze the current column, allowing you to move the selected position in
> the tree to another node, and locking the nodes for column 2 etc etc

Ok, but I still think it makes sense to implement this with the
free-layout system, so that your grid could be a separate window, or
not, as desired.  free-layout is basically nested QSplitters, so it can
represent a grid, but with more flexibility (cell 1,0 doesn't have to
be the same height as cell 0,0, etc.)
.. @+node:ekr.20130806072439.21472: *5* Re: UI idea: body editors in a grid
From: Matt Wilkie <maphew@gmail.com>

> That is, you would edit and view all the children of the currently
> focused node all at once.

I often use "Edit in notepad" (or more likely pyscripter) for this
purpose. It would be nice to stay inside Leo; I sometimes lose data by
forgetting which editor has the most current version.
.. @+node:ekr.20130806072439.21473: *5* Re: UI idea: body editors in a grid
From: Terry Brown <terry_n_brown@yahoo.com>

On Wed, 18 Apr 2012 21:42:21 +0300
"Ville M. Vainio" <vivainio@gmail.com> wrote:

> I am bringing another angle into play here - systematic selection of what
> nodes are shown in the editors, in the proposed scheme we would have a
> single column of editors, each displaying every child of currently selected
> node.
> 
> Expanding the scope to a grid, we could have a grid-lock-column that would
> freeze the current column, allowing you to move the selected position in
> the tree to another node, and locking the nodes for column 2 etc etc

Ok, but I still think it makes sense to implement this with the
free-layout system, so that your grid could be a separate window, or
not, as desired.  free-layout is basically nested QSplitters, so it can
represent a grid, but with more flexibility (cell 1,0 doesn't have to
be the same height as cell 0,0, etc.)
.. @+node:ekr.20130806072439.21474: *5* Re: UI idea: body editors in a grid
From: Kent Tenney <ktenney@gmail.com>

On Wed, Apr 18, 2012 at 10:53 AM, Terry Brown <terry_n_brown@yahoo.com> wro=
te:
> On Wed, 18 Apr 2012 12:37:22 +0300
> "Ville M. Vainio" <vivainio@gmail.com> wrote:
>
>> How about taking this idea further and locking the body editors in a
>> grid, or column?
>
> When the body editor is a well behaved widget it should be straight
> forward to place them where ever you want in using the free-layout
> mechanism.

Plus, free-layout provides persistence: it's worth putting effort into
configuring pane configuration because it will be available next time.

(I guess I'm persistent about wanting persistence)
.. @+node:ekr.20130806072439.21475: *5* Re: UI idea: body editors in a grid
From: Terry Brown <terry_n_brown@yahoo.com>

On Wed, 18 Apr 2012 12:57:03 -0700 (PDT)
"Edward K. Ream" <edreamleo@gmail.com> wrote:

> As I was thinking about doing body editors with free_layout (and by
> extension, the tabula editors) I had another new thought: it's time to
> replace the present difficult selection code with a broadcaster/
> listener framework.

Although such a framework might be quite useful, I can't help thinking
it would insert a big delay between now and getting flexible body
editors implemented.

> In particular, the multiple body editor code is on the verge of
> collapse because it tries to figure out too much in a spaghetti-like
> mass of logic.  This doesn't generalize, and Leo is becoming so
> "exuberant" in its IDE that a simpler, more general mechanism is
> becoming essential.

I think that getting body editors working as described in my recently
bumped "Free range body editors" post would not be that hard, certainly
simpler and faster than a broadcaster / listener framework.  And the
current multiple body editors code could just be dropped completely, so
while I suspect you're right about it being on the edge of implosion, I
don't think that's a problem :-)
.. @+node:ekr.20130806072439.21476: *5* Re: UI idea: body editors in a grid
From: "Ville M. Vainio" <vivainio@gmail.com>

--20cf305b11c06d69c404bdf86a61


I am bringing another angle into play here - systematic selection of what
nodes are shown in the editors, in the proposed scheme we would have a
single column of editors, each displaying every child of currently selected
node.

Expanding the scope to a grid, we could have a grid-lock-column that would
freeze the current column, allowing you to move the selected position in
the tree to another node, and locking the nodes for column 2 etc etc

.. @+node:ekr.20130806072439.21477: *5* Re: UI idea: body editors in a grid
From: "Ville M. Vainio" <vivainio@gmail.com>

Have you tried alt-x stickynote from stickynotes plugin?

.. @+node:ekr.20130806072439.21478: *5* Re: UI idea: body editors in a grid
From: Terry Brown <terry_n_brown@yahoo.com>

On Wed, 18 Apr 2012 11:45:25 -0500
Terry Brown <terry_n_brown@yahoo.com> wrote:

> Another feature I've wanted to add to free_layout is popping out any
> element into its own window (replacing sticky-notes).  You could go one
> better and pop-out free-layout frames which could contain multiple
> widgets, like tabula currently does.
> 
> I'll try and get those features into free-layout.

Woohoo - done and pushed.  Went for the second option, instead of
pop-out windows holding a single widget, they hold a whole new
free-layout hierarchy, which of course can be a single widget, or much
more, if you want.  See the 'Open Window' command on the free-layout
splitter handle context menu.

Even made a screencast to demonstrate, but unfortunately the sound was
useless, despite being ok in trials before hand.  Might try again later.
.. @+node:ekr.20130806072439.21479: *5* Re: UI idea: body editors in a grid
From: Terry Brown <terry_n_brown@yahoo.com>

On Wed, 18 Apr 2012 12:37:22 +0300
"Ville M. Vainio" <vivainio@gmail.com> wrote:

> How about taking this idea further and locking the body editors in a
> grid, or column?

When the body editor is a well behaved widget it should be straight
forward to place them where ever you want in using the free-layout
mechanism.  I think that's a better goal, it allows you more
flexibility in terms of maybe one small (both dimensions) and one large
editor, for example.
.. @+node:ekr.20130806072439.21480: *5* Re: UI idea: body editors in a grid
From: "Edward K. Ream" <edreamleo@gmail.com>

On Apr 18, 1:42=A0pm, "Ville M. Vainio" <vivai...@gmail.com> wrote:
> I am bringing another angle into play here - systematic selection of what
> nodes are shown in the editors, in the proposed scheme we would have a
> single column of editors, each displaying every child of currently select=
ed
> node.

The new broadcaster/listener framework should probably be designed to
handle this.  That is, in the new framework it should explicitly be
possible to select multiple nodes.


> Expanding the scope to a grid, we could have a grid-lock-column that woul=
d
> freeze the current column, allowing you to move the selected position in
> the tree to another node, and locking the nodes for column 2 etc etc
> On Apr 18, 2012 6:53 PM, "Terry Brown" <terry_n_br...@yahoo.com> wrote:

Interesting.  For some purposes the column would be like a "super
node", that is, an explicit collection of nodes.

EKR

.. @+node:ekr.20130806072439.21481: *5* Re: UI idea: body editors in a grid
From: Terry Brown <terry_n_brown@yahoo.com>

On Wed, 18 Apr 2012 11:12:45 -0500
"Edward K. Ream" <edreamleo@gmail.com> wrote:

> > When the body editor is a well behaved widget it should be straight
> > forward to place them where ever you want in using the free-layout
> > mechanism.  
> 
> Are you suggesting doing free-layout in tabula?

No, although that gives me another idea...

Another feature I've wanted to add to free_layout is popping out any
element into its own window (replacing sticky-notes).  You could go one
better and pop-out free-layout frames which could contain multiple
widgets, like tabula currently does.

I'll try and get those features into free-layout.  Note that a couple
of widgets already have their own pop-out capability, the body editor
and view-rendered.

Also some frame manipulation tools in free-layout would be good.  To
maximize / restore one frame, and layout frames in a grid, if there was
an intent to replace tabula.

Not that tabular needs replacing, but I think it's benefits can be
generalized.
.. @+node:ekr.20130806072439.21337: *4* Wanted: better C importer
From: ne1uno <eltronis@gmail.com>

wouldn't it be great to have a first class c importer?
hiding the complexity of platform & compiler/option #defines.
invisible (TM) nodes would be fruitful here. switched on by @#define.
with an @#define=3D collection node or using a bunch of headlines.
and an rclick flipper for true/false, defined/not defined
declarations.

we know c isn't disappearing. quite a few people still regard
any so called scripting language as a nuisance.
maybe ok for prototyping but not for the final product.
pyqt would be near zilch useful w/o Qt, at least currently.
I guess that's as far as I ever got, wouldn't it be great if...

meanwhile I wait for the inspiration or someone else to nail down
a regular expression c language parser. maybe a tokenizer is enough.
I did run c code through AStyle then through your old c2py via
buttons.
for code that would remain in c,
in SciTE through google CPPlint program to point up flaws,
and to get the context sensitive help from various CHM.
running flawfinder good to do now and then old or new code.
post processing and displaying the report in a browser.
but it doesn't go far enough & too many false positives.

there is splint, maybe the only free lint left. the need to inject
"hints" all over the code make it less than ideal for perusing
unknown source and generally a deal breaker for project code.
sometimes all you need is a function/var list to get by.
deeper static analysis is quite the serious business. so, it's
not a surprise those programs are not easily found, or used.
there are a few code flow programs that could be harnessed
to colorize headlines indicating relations.
taking all this in, marking nodes that need work with a popup
or tooltip action event when you view that node with the
details of one or another parser to annotate what needs work.

we have had a few plugins/buttons/attempts at designing an
interface to get a program node compiled. this is also a decent
way to get info on the quality of code by turning all warnings on.
fails for snippits. never quite simple to hookup or modify painless.
perhaps the biggest problem is knowing what is available and where.
more toolbars, no reason they can't dock. drag & dropping buttons.
one of the huge advantages of Qt over Tk so far barely tapped.
you begin to accept the fact that you need to create a temp file
instead of real process control. managing program quirks
& options becomes more trouble than it's worth just to
protect the purity of the operation sans temp files.
QTprocess has more options than the process in pythons libs.
if it ever works as well as it should. but, a little hard to wrap.
not going to venture a guess if pyqt gets it right or not.
not to mention how bungled up OS process control still is.
process control will be essential to any inter-process operations.
that is, unless you backslide into wanting to build everything "in"
and invent everything new again. re: blender, I haven't looked at
blender code in a while, but I would be shocked if there weren't
some well established way to hook into a script.
sounds like noone has found them yet.

not sure how to grab a window handle on other OS but for windows
it's fairly straight forward. blender or GTK could setup blocks.
another great Qt based project is universal indenter, a front end

for many indenters for many languages. this would be a good place
to look for how to manage inter-process communication in Qt.
a first class editor will have to include first class importer for
javascript at the least and probably lua and one or two others.
one could imagine niceties like clickable links on #include files.
right clickable options on them such as import, simple view, htmlize.

also about styles, astyle has the options on the commandline, the
builtin/compiled in defaults and an ~/.astyle.rc for personal style.
some will find an indenter that has no options useless. I know the
indenter created is purely for internal use, as it were, at this
point.
adding selectable options later will complicate the program and for
most use will have little payback. you may as well expect to have some
want a plugable option for style.
exposing a general use tokenizer could have many callers.
.. @+node:ekr.20130806072439.21482: *4* Wish list: xiki window for leo
@nocolor

From: wgw <wgwinder@gmail.com>

Xiki.org gives a demo of a "wiki" shell for command execution. Leo should 
be able to do the same thing (and more!), in the sense that leoscreen, for 
example, has two way communication with the command line. I suppose a 
"Lxiki" is really just a question of setting up the right shortcuts (like a 
shift-ctrl-b that would run highlighted python code from the command 
line... with a tmp file?).

Just an idea for the Leo melting pot. 

.. @+node:ekr.20130806072439.21483: *5* Re: Wish list: xiki window for leo
@nocolor

From: wgw <wgwinder@gmail.com>

Thanks for the tip -- it will take me a while to get my head around vspace
(will keep an eye on Ville's blog post).

I'm just beginning to appreciate (or imagine) what Ipython, sublime text
editor, leo, xiki, etc could mean for some kind of intelligent document
workbench. Of course the big hurdle is not so much the string processing
(sublime is a good example of how that can be done), but rather the syntax
processing -- i.e. the docbench  (to coin a phrase) should understand the
syntax of whatever is being input and then offer syntax-aware functions....
Sorry, getting a little obscure: all I mean by syntax-aware is the ability
to propose text completions (Leo's autocompletion is a good example --
everything should work like autocomplete!) and allow for intelligent text
changes depending on a database of information (for example, a search and
replace that would  know how to search on "caterpillar" and turn it into
"butterfly" but would not touch "caterpillar truck").

Seems like Leo is not far from doing that synthesis, but it would require
more database integration. So for example, even the python help system does
not have autocomplete. (No criticism there! The great thing about Leo is
that if you want something, you just have to dive in and build it. My day
job might just let me do that!)
.. @+node:ekr.20130806072439.21484: *5* Re: Wish list: xiki window for leo
@nocolor

From: Terry Brown <terry_n_brown@yahoo.com>

> Thanks for the tip -- it will take me a while to get my head around vspace
> (will keep an eye on Ville's blog post).

Just to clarify, vs-eval, vs-last, vs-last-pretty are quite straight
forward, as I described them below, and do not require comprehension of
the esoterica of value-space :-) I just put them in that plugin (a) to
avoid creating yet another plugin, and (b) because it seemed sensible
to have them use the value-space namespace c.vs, but all that means for
vs-eval, vs-last, vs-last-pretty is that

  a =3D 7

executed by vs-eval assigns a value to a which can be used by
subsequent vs-eval calls (persistent for the lifetime of the session).

For example, make a body with this text

a =3D 7
b =3D 3
a + b

and place the cursor in front of the first 'a'

execute (Alt-x or key binding) vs-eval 4 times

 - first time executes the empty selection and selects the next line
 - second time assigns 7 to a and report 7 in the log
 - third time assigns 3 to b and report 3 in the log
 - forth time calculates a + b and report 10 in the log

executing vs-last(-pretty) would insert the last result (None, 7, 3,
10) in the body.
.. @+node:ekr.20130806072439.21485: *5* Re: Wish list: xiki window for leo
@nocolor

From: wgw <wgwinder@gmail.com>

Got it! The value of valuespace (!) is that that you can make a pythonesque
session persist. I did not realize that there was no direct two-way bridge
to the python window that leo launches. Even if there were, we would want
to make the session persist by logging it into the outline, as
valuespace (vs-create-tree) does.
.. @+node:ekr.20130806072439.21487: *5* Re: Wish list: xiki window for leo
@nocolor

From: Terry Brown <terry_n_brown@yahoo.com>

In addition to the outline as a active data document functions of
Ville's value-space plugin, I recently added some simple ;-) commands:

Alt+A vs-eval
Alt+S vs-last
Alt+D vs-last-pretty
(my key bindings)

vs-eval evaluates the selected python in the c.vs namespace.  It makes
an effort to workout what the output should be, and puts it in the
log.  It captures print output to the log too.  It selects the next
line, ready for execution.

vs-last inserts the last result into the body, and vs-last-pretty
does the same, but using pprint formatting.

Ctrl-B also runs the script in the body, but not in a persistent
namespace, running only the selected text doesn't seem to be working,
and it doesn't work so hard to work out the output.

I guess leoscreen would do the same things as the vs-* commands if you
used it against a python shell.  The inspiration for the vs-* commands
was wanting Leo to tell you what 3.57 * 365 / 12 was without a lot of
effort, but of course you can define functions etc. etc.
.. @+node:ekr.20130812034101.12580: *3* Installation wishlist
@language rest
.. @+node:ekr.20130806072439.20650: *4* Wishlist: brew install leo
From: Winn Dixie <incredible0n3@gmail.com>

Would be stellar to have a brew install leo (for Mac OSX 10.7.X) with
possible built in options to install vim bindings.
.. @+node:ekr.20130806072439.20732: *4* Runnable Leo in one .zip file.
From: Terry Brown <terry_n_brown@yahoo.com>

Summary - it's easy to make a .zip file containing Leo and all it's
dependencies.

Inspired by Matt's recipe, using VirtualBox throw away 1GB Windows XP
32 bit machines, I tried the following.

Install Python (installer from python.org) 2.7.2 to 

  C:\Docouments and Settings\someuser\Desktop\leo\python27

Install PyQt (installer from Riverbank) 4.9 into the same folder (it
goes there by default)

Unzip http://www.greygreen.org/leo/leo-editor-latest.zip into

  C:\Docouments and Settings\someuser\Desktop\leo\leo-editor-latest

Make leo.zip from C:\Docouments and Settings\someuser\Desktop\leo

Delete the virtual machine, purging any registry entries etc. created
by the two installers.

On a fresh machine, searched the registry for 'python' just to be sure,
found nothing.

Unzip the .zip file, then

  cd C:\Docouments and Settings\someuser\Desktop\leo
  python27\python.exe leo-editor-latest\launchLeo.py

And Leo opens a blank outline, after asking for an ID, as it's supposed
to.  Didn't test it beyond that.

So, the .zip file contains all Leo needs to run, and obviously
runLeo.bat could be added in the top level to actually launch it.

Of course this is for Windows, so I think it's an improvement over
asking people to install Python and PyQt first, but neither of those
steps was that hard in Windows anyway.

===== EKR

Is this a technique that we could use for official Windows releases?
If so, what exactly would we do?

===== Terry

I guess, perhaps as an all-in-one option with a system integrated
option for those who want to use system python/qt.  Don't know if it
violates and licensing on Python / Qt, everything's being distributed
unaltered, so I wouldn't think so.

So basically you'd give people a large .zip file and tell them to
extract it to a folder and run the batchfile at the top level.  If they
can't do that, they might not be ready for Leo :-)  I guess you could
make it a self-extracting .zip, for that matter.

Also, the daily snapshot could be made this way, seeing once Python and
Qt are installed in the folder the Leo version can just be copied in.

It's not uncommon for FLOSS to be distributed this way, both Blender
and Inkscape use this approach, particularly for recent builds.

===== From: HansBKK <hansbkk@gmail.com>

If something like this **is** done, it should IMO be packaged as an
alternative to the normal installation procedure.

You would definitely get marketing exposure by getting the specs from
PortableApps.com and let them host it there as  "Portable Leo", tracking
the "official" Portable Python (currently 2.7.2) as a dependency, obviously
including QT etc as well. But it would need to be kept up to date. . .

Most Windows users would be better served by following the normal
installation procedure and ending up with a
registry-and-environment-variables-complete install of Python et al which
they can use for other things beyond Leo. Ending up with multiple instances
of Python to maintain is likely to cause more problems.

And the normal Windows install just isn't that hard, really! Improving the
current instructions, by providing a step-by-step "cookbook" with direct
links to the download packages etc might make it a **little** easier (IMO
only for the clueless), but then of course that would be a doc that would
need pretty frequent updates, which if I may be so bold doesn't seem to
happen too quickly on the doc side.
.. @+node:ekr.20130806072439.20736: *5* Re: Runnable Leo in one .zip file.
From: Matt Wilkie <maphew@gmail.com>

Since this topical today, almost a year later, I thought I'd take a run at 
repeating this using Portable Python (http://www.portablepython.com) as a 
base. It didn't work, but I think it should. Maybe someone else knows why. 

I ran the installer for 2.7.3 since 3.2 doesn't include PyQt4. At install 
time I selected only the Python and PyQt4 packages. Then from a fresh 
command shell:

{{{
path=c:\windows;c:\windows\system32
pushd x:\portapy27\App
path=%cd%;%cd%\Scripts;%cd%\Lib\site-packages\PyQt4;%path%
set pythonhome=%cd%
set pythonpath=%cd%\Lib

popd

python --version
Python 2.7.3

python -c "import PyQt4"
:: no error returned, we're good.

python c:\apps\leo-editor-latest\launchLeo.py
Leo requires Qt to be installed.
}}}

oh well.
.. @+node:ekr.20130806072439.20744: *5* Re: Runnable Leo in one .zip file.
From: HansBKK <hansbkk@gmail.com>

> PortableApps version would be FANTASTIC!!

A couple of versions have been posted here already, including Terry's very
simple sequence in the first message of this thread. Of course, we're only
talking about Windows, but note that it works equally well either syncing
with whatever tool (I favor Unison over SSH) or carrying around on an
arbitrary-path'd external device, including flash drives (but they can be
slow).

Here's my more robust (hence more complex) version, xx indicating your 
python version (mine is 27):

Use the normal .MSI, setup.exe etc processes to Install a clean "canonical" 
version of your "python dev stack" to say C:\PythonXX, reboot if needed, 
test thoroughly. Note any new environment variables pointing to your new 
binary locations.

Now create a corresponding PythonXX folder in your "PortableApps" location 
(I put it under "CommonFiles" along with GTK and Java) and copy everything 
from your installed location to the portable one.

You can then use the project-provided tools on the "master" computer to 
keep your binaries updated, and they will see any local Registry entries 
and the environment variables they created and operate normally wrt your 
installed location (e.g. C:\PythonXX).

If you have a local folder sync tool (I use Unison and WinMerge) you can 
add to/remove from/configure your Python environment from either location, 
otherwise just keep your installed location as the "master" and just copy 
the whole stack over each time you do so.

The whole PortableApps tree can then be sync'd/copied to any other 
desktop(s) you like, either over the wire or via an external device, and 
the latter can be carried for use in say an Internet cafe or client-site 
situation.

====================

For use on those other computers, for running in portable mode, I use a
"portable start menu" (PStart) which allows for its own "autolaunch" batch
files, where I set some global environment variables to be used by
app-specific launch batch files, including :

%Path% (I add my batch folder and a general utility/tools folder)
%HOME% (usually "E:\aasync\Data\H_HOME"
and a custom one called %h_pa%, which points to the root of my PortableApps 
parent (usually "D:\aasync\PortableApps")

Then for each environment that requires its own custom settings, I create a 
launch batch file that builds on that base. In the case of Python apps, 
here's an example that opens a CMD console window:

@ECHO OFF
set 
PATH=%PATH%;%h_pa%\CommonFiles\Python27;%h_pa%\CommonFiles\Python27\Lib\site-packages\PyQt4;%h_pa%\CommonFiles\Python27\Lib\idlelib;%h_pa%\CommonFiles\Python27\Scripts;
set PROMPT=$p_python$g
E:
cd \aasync
CMD.exe

I'm not sure which if any of the environment stuff Leo requires, but I 
figure it might as well have the same environment as my Python CLI, since 
I'll be testing shell integration, including iPython. In my leo-win.bat, 
the last three lines above are replaced with:

D:
cd \aasync\PortableApps\leo-editor
start "" "..\CommonFiles\Python27\pythonw.exe" 
"..\CommonFiles\Python27\Lib\site-packages\leo-editor4\launchLeo.py" %*

====================

Note this is more than the minimum you need to just run Leo - you could of 
course simplify it; for example, only set the environment variables Leo 
requires, or you could just set the master computer' installation routines 
to use a single location under PortableApps, but I prefer to keep them 
separate for testing purposes.

I hope you (and others googling this later) find this useful.
.. @+node:ekr.20130807203905.16594: *4* Wishlist for newbies (Fidel)
@language rest

From the thread: "Associate .Leo files to open with Leo when double click"

From: <fidelperez@gmail.com>

I guess others have had this idea but It would be great to include a small
file within the Quickstart guide which would associate files automatically.
(Or maybe asking for imput, which can be done through a Leo node and this
way the user learns about its functionality).

Also, I miss some more buttons or scripts in quick start guide, preferably
before the "programming" section, so when a new user opens it, he has had
the opportunity to do Ctrl+B on several scripts (for instance, showing in
the log the name of all the nodes within the selected one, having some
subnodes with numbers and doing math on them and showing the result on the
log pane, and as much "silly" but visual functions as possible so the user,
by going pressing ctrl+b on each, gets a bigger chance to understand what
is Leo. In my oppinion some users will just stop in the quickguide if they
are not presented with such a thing before going to docs.leo etc.

Another thing is the plugin activation, the description of the plugins is
not as accessible as it should be (opinions here, focusing in new users,
and as I always say, appreciating and fully grateful for Leo as is now),and
a script for activating them easier, been a week using Leo and still cant
quite activate, find the descriptions or use them freely... And if each
plugin or script had an example of use that would be priceless, for
instance, including them all in quickstart (both scripts, plugins branchs)
and then the new user could just go through all clicking on the examples
and just seeing Leo work and show its potential. I know some of those are
done but as I said, after a week or so I still am very confused...

Also, quickstartguide should be open by default (instead of current
Leo workbook) at least until the user changes some config and prevents that
from happening. Is there any "load previous tabs" functionality? (IE open
the Leo files which where open when it was closed the last time)
  
.. @+node:ekr.20130807203905.16596: *4* PortableFileAssociator
From the thread: Cannot open Leo files by double-click in Windows Explorer?
From: HansBKK <hansbkk@gmail.com>

For those like me who work in "portable" mode, there's a very cool tool
called "PortableFileAssociator" that allows you to create a set of windows
file associations, icons etc and enable/disable the whole profile at one
time, without messing with the local system's registry.

Also handy for those not in portable mode, but working on different windows
boxes and bored with having to tweak each one separately.
.. @+node:ekr.20121005105428.12866: *3* Ipython notebook stuff
.. @+node:ekr.20121005105428.10112: *4* ipynb example
{
  "metadata": {
    "name": "Part 2: Dataset Basics and Concepts"
  }, 
  "nbformat": 3, 
  "nbformat_minor": 0, 
  "worksheets": [
    {
      "cells": [
        {
          "cell_type": "heading", 
          "level": 1, 
          "metadata": {}, 
          "source": [
            "Part 2: Dataset Basics and Concepts"
          ]
        }, 
        {
          "cell_type": "markdown", 
          "metadata": {}, 
          "source": [
            "- - -\n*Note*", 
            "\n\n", 
            "This tutorial part is also available for download as an ", 
            "[IPython notebook][IPython notebook]:\n[", 
            "[ipynb][ipynb]]", 
            "- - -\n"
          ]
        }, 
        {
          "cell_type": "markdown", 
          "metadata": {}, 
          "source": [
            "\n\n", 
            "A ", 
            "[Dataset](http://pymvpa.org/generated/mvpa2.datasets.base.Dataset.html#mvpa2-datasets-base-dataset) is the basic data container in PyMVPA. It\nserves as the primary form of input data storage, but also as container for\nmore complex results returned by some algorithm. In this tutorial part we will\ntake a look at what a dataset consists of, and how it works.\n\n", 
            "In the simplest case, a dataset only contains ", 
            "*data* that is a matrix of\nnumerical values."
          ]
        }, 
        {
          "cell_type": "code", 
          "collapsed": false, 
          "input": [
            "from mvpa2.tutorial_suite import *\n", 
            "data = [[  1,  1, -1],\n        [  2,  0,  0],\n        [  3,  1,  1],\n        [  4,  0, -1]]\n", 
            "ds = Dataset(data)\n", 
            "ds.shape"
          ], 
          "language": "python", 
          "metadata": {}, 
          "outputs": []
        }, 
        {
          "cell_type": "code", 
          "collapsed": false, 
          "input": [
            "len(ds)"
          ], 
          "language": "python", 
          "metadata": {}, 
          "outputs": []
        }, 
        {
          "cell_type": "code", 
          "collapsed": false, 
          "input": [
            "ds.nfeatures"
          ], 
          "language": "python", 
          "metadata": {}, 
          "outputs": []
        }, 
        {
          "cell_type": "code", 
          "collapsed": false, 
          "input": [
            "ds.samples"
          ], 
          "language": "python", 
          "metadata": {}, 
          "outputs": []
        }, 
        {
          "cell_type": "markdown", 
          "metadata": {}, 
          "source": [
            "\n\n", 
            "In the above example, every row vector in the `data` matrix becomes an\nobservation or a ", 
            "[sample](http://pymvpa.org/glossary.html#term-sample) in the dataset, and every column vector\nrepresents an individual variable or a ", 
            "[feature](http://pymvpa.org/glossary.html#term-feature). The concepts of samples\nand features are essential for a dataset, hence we take a further, closer look.\n\n", 
            "The dataset assumes the first axis of the data to be the samples separating\ndimension. If the dataset is created using a one-dimensional vector it will\ntherefore have as many samples as elements in the vector, and only one feature."
          ]
        }, 
        {
          "cell_type": "code", 
          "collapsed": false, 
          "input": [
            "one_d = [ 0, 1, 2, 3 ]\n", 
            "one_ds = Dataset(one_d)\n", 
            "one_ds.shape"
          ], 
          "language": "python", 
          "metadata": {}, 
          "outputs": []
        }, 
        {
          "cell_type": "markdown", 
          "metadata": {}, 
          "source": [
            "\n\n", 
            "On the other hand, if a dataset is created from multi-dimensional data, only its\nsecond axis represents the features"
          ]
        }, 
        {
          "cell_type": "code", 
          "collapsed": false, 
          "input": [
            "import numpy as np\n", 
            "m_ds = Dataset(np.random.random((3, 4, 2, 3)))\n", 
            "m_ds.shape"
          ], 
          "language": "python", 
          "metadata": {}, 
          "outputs": []
        }, 
        {
          "cell_type": "code", 
          "collapsed": false, 
          "input": [
            "m_ds.nfeatures"
          ], 
          "language": "python", 
          "metadata": {}, 
          "outputs": []
        }, 
        {
          "cell_type": "markdown", 
          "metadata": {}, 
          "source": [
            "\n\n", 
            "In this case we have a dataset with three samples and four features, where each\nfeature is a 2x3 matrix. In case somebody is wondering now, why not simply each\nvalue in the data array is considered as its own feature (yielding 24 features)\n-- stay tuned, as this is going to be of importance later on."
          ]
        }, 
        {
          "cell_type": "heading", 
          "level": 2, 
          "metadata": {}, 
          "source": [
            "Attributes"
          ]
        }, 
        {
          "cell_type": "markdown", 
          "metadata": {}, 
          "source": [
            "\n\n", 
            "What we have seen so far does not really warrant the use of a dataset over a\nplain array or a matrix with samples. However, in the MVPA context we often need\nto know more about each samples than just the value of its features.  In the\nprevious tutorial part we have already seen that per-sample ", 
            "[target](http://pymvpa.org/glossary.html#term-target)\nvalues are required for supervised-learning algorithms, and that a dataset\noften has to be split based on the origin of specific groups of samples.  For\nthis type of auxiliary information a dataset can also contain collections of\nthree types of ", 
            "[attribute](http://pymvpa.org/glossary.html#term-attribute)s: ", 
            "[sample attribute](http://pymvpa.org/glossary.html#term-sample-attribute), ", 
            "[feature attribute](http://pymvpa.org/glossary.html#term-feature-attribute), and\n", 
            "[dataset attribute](http://pymvpa.org/glossary.html#term-dataset-attribute)."
          ]
        }, 
        {
          "cell_type": "heading", 
          "level": 3, 
          "metadata": {}, 
          "source": [
            "For Samples"
          ]
        }, 
        {
          "cell_type": "markdown", 
          "metadata": {}, 
          "source": [
            "\n\n", 
            "In a dataset each ", 
            "[sample](http://pymvpa.org/glossary.html#term-sample) can have an arbitrary number of additional\nattributes. They are stored as vectors of the same length as the number of samples\nin a collection, and are accessible via the `sa` attribute. A collection is\nderived from a standard Python ", 
            "`dict`, and hence adding sample attributes\nworks identical to adding elements to a dictionary:"
          ]
        }, 
        {
          "cell_type": "code", 
          "collapsed": false, 
          "input": [
            "ds.sa['some_attr'] = [ 0., 1, 1, 3 ]\n", 
            "ds.sa.keys()"
          ], 
          "language": "python", 
          "metadata": {}, 
          "outputs": []
        }, 
        {
          "cell_type": "markdown", 
          "metadata": {}, 
          "source": [
            "\n\n", 
            "However, sample attributes are not directly stored as plain data, but for\nvarious reasons as a so-called ", 
            "[Collectable](http://pymvpa.org/generated/mvpa2.base.collections.Collectable.html#mvpa2-base-collections-collectable) that in\nturn embeds a NumPy array with the actual attribute:"
          ]
        }, 
        {
          "cell_type": "code", 
          "collapsed": false, 
          "input": [
            "type(ds.sa['some_attr'])"
          ], 
          "language": "python", 
          "metadata": {}, 
          "outputs": []
        }, 
        {
          "cell_type": "code", 
          "collapsed": false, 
          "input": [
            "ds.sa['some_attr'].value"
          ], 
          "language": "python", 
          "metadata": {}, 
          "outputs": []
        }, 
        {
          "cell_type": "markdown", 
          "metadata": {}, 
          "source": [
            "\n\n", 
            "This \"complication\" is done to be able to extend attributes with additional\nfunctionality that is often needed and can offer significant speed-up of\nprocessing. For example, sample attributes carry a list of their unique values.\nThis list is only computed once (upon first request) and can subsequently be\naccessed directly without repeated and expensive searches:"
          ]
        }, 
        {
          "cell_type": "code", 
          "collapsed": false, 
          "input": [
            "ds.sa['some_attr'].unique"
          ], 
          "language": "python", 
          "metadata": {}, 
          "outputs": []
        }, 
        {
          "cell_type": "markdown", 
          "metadata": {}, 
          "source": [
            "\n\n", 
            "However, for most interactive uses of PyMVPA this type of access to attributes'\n`.value` is relatively cumbersome (too much typing), therefore collections offer direct\nattribute access by name:"
          ]
        }, 
        {
          "cell_type": "code", 
          "collapsed": false, 
          "input": [
            "ds.sa.some_attr"
          ], 
          "language": "python", 
          "metadata": {}, 
          "outputs": []
        }, 
        {
          "cell_type": "markdown", 
          "metadata": {}, 
          "source": [
            "\n\n", 
            "Another purpose of the sample attribute collection is to preserve data\nintegrity, by disallowing improper attributes:"
          ]
        }, 
        {
          "cell_type": "code", 
          "collapsed": false, 
          "input": [
            "ds.sa['invalid'] = 4"
          ], 
          "language": "python", 
          "metadata": {}, 
          "outputs": []
        }, 
        {
          "cell_type": "code", 
          "collapsed": false, 
          "input": [
            "ds.sa['invalid'] = [ 1, 2, 3, 4, 5, 6 ]"
          ], 
          "language": "python", 
          "metadata": {}, 
          "outputs": []
        }, 
        {
          "cell_type": "markdown", 
          "metadata": {}, 
          "source": [
            "\n\n", 
            "But other than basic plausibility checks no further constraints on values of\nsamples attributes exist. As long as the length of the attribute vector matches\nthe number of samples in the dataset, and the attributes values can be stored\nin a NumPy array, any value is allowed. For example, it is perfectly possible\nand supported to store literal attributes. It should also be noted that each\nattribute may have its own individual data type, hence it is possible to have\nliteral and numeric attributes in the same dataset."
          ]
        }, 
        {
          "cell_type": "code", 
          "collapsed": false, 
          "input": [
            "ds.sa['literal'] = ['one', 'two', 'three', 'four']\n", 
            "sorted(ds.sa.keys())"
          ], 
          "language": "python", 
          "metadata": {}, 
          "outputs": []
        }, 
        {
          "cell_type": "code", 
          "collapsed": false, 
          "input": [
            "for attr in ds.sa:\n   print \"%s: %s\" % (attr, ds.sa[attr].value.dtype.name)"
          ], 
          "language": "python", 
          "metadata": {}, 
          "outputs": []
        }, 
        {
          "cell_type": "heading", 
          "level": 3, 
          "metadata": {}, 
          "source": [
            "For Features"
          ]
        }, 
        {
          "cell_type": "markdown", 
          "metadata": {}, 
          "source": [
            "\n\n", 
            "[Feature attribute](http://pymvpa.org/glossary.html#term-feature-attribute)s are almost identical to ", 
            "[sample attribute](http://pymvpa.org/glossary.html#term-sample-attribute)s the ", 
            "*only* difference is that instead of having one attribute value per\nsample, feature attributes have one value per (guess what? ...) ", 
            "*feature*.\nMoreover, they are stored in a separate collection in the datasets that is\ncalled `fa`:"
          ]
        }, 
        {
          "cell_type": "code", 
          "collapsed": false, 
          "input": [
            "ds.nfeatures"
          ], 
          "language": "python", 
          "metadata": {}, 
          "outputs": []
        }, 
        {
          "cell_type": "code", 
          "collapsed": false, 
          "input": [
            "ds.fa['my_fav'] = [0, 1, 0]\n", 
            "ds.fa['responsible'] = ['me', 'you', 'nobody']\n", 
            "sorted(ds.fa.keys())"
          ], 
          "language": "python", 
          "metadata": {}, 
          "outputs": []
        }, 
        {
          "cell_type": "heading", 
          "level": 3, 
          "metadata": {}, 
          "source": [
            "For The Dataset"
          ]
        }, 
        {
          "cell_type": "markdown", 
          "metadata": {}, 
          "source": [
            "\n\n", 
            "Finally, there can be also attributes, not per each sample, or each\nfeature, but for the dataset as a whole: so called ", 
            "[dataset](http://pymvpa.org/glossary.html#term-dataset)s. Assigning such attributes and accessing them later on work in\nexactly the same way as for the other two types of attributes, except that dataset\nattributes are stored in their own collection which is accessible via the\n`a` property of the dataset.  However, in contrast to sample and feature\nattribute no constraints on the type or size are imposed -- anything can be\nstored. Let's store a list with all files in the current directory, just\nbecause we can:"
          ]
        }, 
        {
          "cell_type": "code", 
          "collapsed": false, 
          "input": [
            "from glob import glob\n", 
            "ds.a['pointless'] = glob(\"*\")\n", 
            "'setup.py' in ds.a.pointless"
          ], 
          "language": "python", 
          "metadata": {}, 
          "outputs": []
        }, 
        {
          "cell_type": "heading", 
          "level": 2, 
          "metadata": {}, 
          "source": [
            "Slicing, resampling, feature selection"
          ]
        }, 
        {
          "cell_type": "markdown", 
          "metadata": {}, 
          "source": [
            "\n\n", 
            "At this point we can already construct a dataset from simple arrays and\nenrich it with an arbitrary number of additional attributes. But just\nhaving a dataset isn't enough. From part one of this tutorial we already\nknow that we need to be able to select subsets of a dataset for further\nprocessing, and we also know that this is possible with PyMVPA's datasets.\nNow it is time to have a closer look into how it works.\n\n", 
            "Slicing a dataset (i.e. selecting specific subsets) is very similar to\nslicing a NumPy array. It actually works ", 
            "*almost* identical. A dataset\nsupports Python's ", 
            "`slice` syntax, but also selection by boolean masks, and\nindices. The following three slicing operations\nresult in equivalent output datasets, by always selecting every other samples\nin the dataset:"
          ]
        }, 
        {
          "cell_type": "code", 
          "collapsed": false, 
          "input": [
            "ds.samples"
          ], 
          "language": "python", 
          "metadata": {}, 
          "outputs": []
        }, 
        {
          "cell_type": "code", 
          "collapsed": false, 
          "input": [
            "ds[::2].samples"
          ], 
          "language": "python", 
          "metadata": {}, 
          "outputs": []
        }, 
        {
          "cell_type": "code", 
          "collapsed": false, 
          "input": [
            "mask = np.array([True, False, True, False])\n", 
            "ds[mask].samples"
          ], 
          "language": "python", 
          "metadata": {}, 
          "outputs": []
        }, 
        {
          "cell_type": "code", 
          "collapsed": false, 
          "input": [
            "ds[[0, 2]].samples"
          ], 
          "language": "python", 
          "metadata": {}, 
          "outputs": []
        }, 
        {
          "cell_type": "markdown", 
          "metadata": {}, 
          "source": [
            "- - -\n*Exercise*", 
            "\n\n", 
            "Search the `NumPy documentation`_ for the difference between \"basic slicing\"\nand \"advanced indexing\". Especially the aspect of memory consumption\napplies to dataset slicing as well, and being aware of this fact might\nhelp to write more efficient analysis scripts. Which of the three slicing\napproaches above is the most memory-efficient?  Which of the three slicing\napproaches above might lead to unexpected side-effects if output dataset\ngets modified?"
          ]
        }, 
        {
          "cell_type": "code", 
          "collapsed": false, 
          "input": [
            "# you can use this cell to for this exercise"
          ], 
          "language": "python", 
          "metadata": {}, 
          "outputs": []
        }, 
        {
          "cell_type": "markdown", 
          "metadata": {}, 
          "source": [
            "- - -\n", 
            "\n\n", 
            "All three slicing-styles are equally applicable to the selection of feature\nsubsets within a dataset. Remember, features are represented on the second axis\nof a dataset."
          ]
        }, 
        {
          "cell_type": "code", 
          "collapsed": false, 
          "input": [
            "ds[:, [1,2]].samples"
          ], 
          "language": "python", 
          "metadata": {}, 
          "outputs": []
        }, 
        {
          "cell_type": "markdown", 
          "metadata": {}, 
          "source": [
            "\n\n", 
            "By applying a selection by indices to the second axis, we can easily get\nthe last two features of our example dataset. Please note the ", 
            "`:` is supplied\nas first axis slicing. This is the Python way to indicate ", 
            "*take everything\nalong this axis*, hence including all samples.\n\n", 
            "As you can guess, it is also possible to select subsets of samples and\nfeatures at the same time."
          ]
        }, 
        {
          "cell_type": "code", 
          "collapsed": false, 
          "input": [
            "subds = ds[[0,1], [0,2]]\n", 
            "subds.samples"
          ], 
          "language": "python", 
          "metadata": {}, 
          "outputs": []
        }, 
        {
          "cell_type": "markdown", 
          "metadata": {}, 
          "source": [
            "\n\n", 
            "If you have prior experience with NumPy you might be confused now. What you\nmight have expected is this:"
          ]
        }, 
        {
          "cell_type": "code", 
          "collapsed": false, 
          "input": [
            "ds.samples[[0,1], [0,2]]"
          ], 
          "language": "python", 
          "metadata": {}, 
          "outputs": []
        }, 
        {
          "cell_type": "markdown", 
          "metadata": {}, 
          "source": [
            "\n\n", 
            "The above code applies the same slicing directly to the NumPy array with\nthe samples, and the result is fundamentally different. For NumPy arrays\nthis style of slicing allows to select specific elements by their indices on\neach axis of an array. For PyMVPA's datasets this mode is not very useful,\ninstead we typically want to select rows and columns, i.e. samples and\nfeatures given by their indices."
          ]
        }, 
        {
          "cell_type": "markdown", 
          "metadata": {}, 
          "source": [
            "- - -\n*Exercise*", 
            "\n\n", 
            "Try to select samples [0,1] and features [0,2,3] simultaneously using\ndataset slicing.  Now apply the same slicing to the samples array itself\n(`ds.samples`) -- make sure that the result doesn't surprise you and find\na pure NumPy way to achieve similar selection."
          ]
        }, 
        {
          "cell_type": "code", 
          "collapsed": false, 
          "input": [
            "# you can use this cell to for this exercise"
          ], 
          "language": "python", 
          "metadata": {}, 
          "outputs": []
        }, 
        {
          "cell_type": "markdown", 
          "metadata": {}, 
          "source": [
            "- - -\n", 
            "\n\n", 
            "One last interesting thing to look at, in the context of dataset slicing\nare the attributes. What happens to them when a subset of samples and/or\nfeatures is chosen? Our original dataset had both samples and feature attributes:"
          ]
        }, 
        {
          "cell_type": "code", 
          "collapsed": false, 
          "input": [
            "print ds.sa.some_attr"
          ], 
          "language": "python", 
          "metadata": {}, 
          "outputs": []
        }, 
        {
          "cell_type": "code", 
          "collapsed": false, 
          "input": [
            "print ds.fa.responsible"
          ], 
          "language": "python", 
          "metadata": {}, 
          "outputs": []
        }, 
        {
          "cell_type": "markdown", 
          "metadata": {}, 
          "source": [
            "\n\n", 
            "Now let's look at what they became in the subset-dataset we previously\ncreated:"
          ]
        }, 
        {
          "cell_type": "code", 
          "collapsed": false, 
          "input": [
            "print subds.sa.some_attr"
          ], 
          "language": "python", 
          "metadata": {}, 
          "outputs": []
        }, 
        {
          "cell_type": "code", 
          "collapsed": false, 
          "input": [
            "print subds.fa.responsible"
          ], 
          "language": "python", 
          "metadata": {}, 
          "outputs": []
        }, 
        {
          "cell_type": "markdown", 
          "metadata": {}, 
          "source": [
            "\n\n", 
            "We see that both attributes are still there and, moreover, also the\nappropriate subsets have been selected."
          ]
        }, 
        {
          "cell_type": "heading", 
          "level": 2, 
          "metadata": {}, 
          "source": [
            "Loading fMRI data"
          ]
        }, 
        {
          "cell_type": "markdown", 
          "metadata": {}, 
          "source": [
            "\n\n", 
            "Enough of theoretical foreplay -- let's look at a concrete example of an\nfMRI dataset. PyMVPA has several helper functions to load data from\nspecialized formats, and the one for fMRI data is\n", 
            "[fmri_dataset()](http://pymvpa.org/generated/mvpa2.datasets.mri.fmri_dataset.html#mvpa2-datasets-mri-fmri-dataset). The example dataset we are going to\nlook at is a single subject from Haxby et al. (2001) that we already\nloaded in part one of this tutorial. For more convenience, and less typing\nwe first specify the path of the directory with the fMRI data."
          ]
        }, 
        {
          "cell_type": "code", 
          "collapsed": false, 
          "input": [
            "path=os.path.join(tutorial_data_path, 'data')"
          ], 
          "language": "python", 
          "metadata": {}, 
          "outputs": []
        }, 
        {
          "cell_type": "markdown", 
          "metadata": {}, 
          "source": [
            "\n\n", 
            "In the simplest case, we now let ", 
            "[fmri_dataset](http://pymvpa.org/generated/mvpa2.datasets.mri.fmri_dataset.html#mvpa2-datasets-mri-fmri-dataset) do its job, by just\npointing it to the fMRI data file. The data is stored as a NIfTI file that has\nall runs of the experiment concatenated into a single file."
          ]
        }, 
        {
          "cell_type": "code", 
          "collapsed": false, 
          "input": [
            "ds = fmri_dataset(os.path.join(path, 'bold.nii.gz'))\n", 
            "len(ds)"
          ], 
          "language": "python", 
          "metadata": {}, 
          "outputs": []
        }, 
        {
          "cell_type": "code", 
          "collapsed": false, 
          "input": [
            "ds.nfeatures"
          ], 
          "language": "python", 
          "metadata": {}, 
          "outputs": []
        }, 
        {
          "cell_type": "code", 
          "collapsed": false, 
          "input": [
            "ds.shape"
          ], 
          "language": "python", 
          "metadata": {}, 
          "outputs": []
        }, 
        {
          "cell_type": "markdown", 
          "metadata": {}, 
          "source": [
            "\n\n", 
            "We can notice two things. First, it worked! Second, we get a\ntwo-dimensional dataset with 1452 samples (these are volumes in the NIfTI\nfile), and over 160k features (these are voxels in the volume). The voxels\nare represented as a one-dimensional vector, and it seems that they have\nlost their association with the 3D-voxel-space. However, this is not the\ncase, as we will see in the next chapter.  PyMVPA represents\ndata in this simple format to make it compatible with a vast range of generic\nalgorithms that expect data to be a simple matrix.\n\n", 
            "We just loaded all data from that NIfTI file, but usually we would be\ninterested in a subset only, i.e. \"brain voxels\".\n", 
            "[fmri_dataset](http://pymvpa.org/generated/mvpa2.datasets.mri.fmri_dataset.html#mvpa2-datasets-mri-fmri-dataset) is capable of performing data masking. We just need to\nspecify a mask image. Such mask image is generated in pretty much any fMRI\nanalysis pipeline -- may it be a full-brain mask computed during\nskull-stripping, or an activation map from a functional localizer. We are going\nto use the original GLM-based localizer mask of ventral temporal cortex\nfrom Haxby et al. (2001). We already know that it comprises 577 voxels.\nLet's reload the dataset:"
          ]
        }, 
        {
          "cell_type": "code", 
          "collapsed": false, 
          "input": [
            "ds = fmri_dataset(os.path.join(path, 'bold.nii.gz'),\n                  mask=os.path.join(path, 'mask_vt.nii.gz'))\n", 
            "len(ds)"
          ], 
          "language": "python", 
          "metadata": {}, 
          "outputs": []
        }, 
        {
          "cell_type": "code", 
          "collapsed": false, 
          "input": [
            "ds.nfeatures"
          ], 
          "language": "python", 
          "metadata": {}, 
          "outputs": []
        }, 
        {
          "cell_type": "markdown", 
          "metadata": {}, 
          "source": [
            "\n\n", 
            "As expected, we get the same number of samples and also only 577 features\n-- voxels corresponding to non-zero elements in the mask image. Now, let's\nexplore this dataset a little further.\n\n", 
            "Besides samples the dataset offers number of attributes that enhance the\ndata with information that is present in the NIfTI image header in the file. Each sample has\ninformation about its volume ID in the time series and the actual acquisition\ntime (relative to the beginning of the file). Moreover, the original voxel\nindex (sometimes referred to as `ijk`) for each feature is available too.\nFinally, the dataset also contains information about the dimensionality\nof the input volumes, voxel size, and any other NIfTI-specific information\nsince it also includes a dump of the full NIfTI image header."
          ]
        }, 
        {
          "cell_type": "markdown", 
          "metadata": {}, 
          "source": [
            "- - -\n*Note*", 
            "\n\n", 
            "Previously (0.4.x versions and 0.5 development prior March 03, 2010),\nPyMVPA exposed 4D (and 3D with degenerate 1st dimension) data in `tkji`\n(corresponds to `tzyx` if volumes were axial slices in\nneurologic convention) order of dimensions.  Now it uses more convenient\norder `tijk` (corresponding to `txyz`), which will match the order exposed\nby NiBabel (PyNIfTI and NiftiImage still expose them as `tkji`).", 
            "- - -\n"
          ]
        }, 
        {
          "cell_type": "code", 
          "collapsed": false, 
          "input": [
            "ds.sa.time_indices[:5]"
          ], 
          "language": "python", 
          "metadata": {}, 
          "outputs": []
        }, 
        {
          "cell_type": "code", 
          "collapsed": false, 
          "input": [
            "ds.sa.time_coords[:5]"
          ], 
          "language": "python", 
          "metadata": {}, 
          "outputs": []
        }, 
        {
          "cell_type": "code", 
          "collapsed": false, 
          "input": [
            "ds.fa.voxel_indices[:5]"
          ], 
          "language": "python", 
          "metadata": {}, 
          "outputs": []
        }, 
        {
          "cell_type": "code", 
          "collapsed": false, 
          "input": [
            "ds.a.voxel_eldim"
          ], 
          "language": "python", 
          "metadata": {}, 
          "outputs": []
        }, 
        {
          "cell_type": "code", 
          "collapsed": false, 
          "input": [
            "ds.a.voxel_dim"
          ], 
          "language": "python", 
          "metadata": {}, 
          "outputs": []
        }, 
        {
          "cell_type": "code", 
          "collapsed": false, 
          "input": [
            "'imghdr' in ds.a"
          ], 
          "language": "python", 
          "metadata": {}, 
          "outputs": []
        }, 
        {
          "cell_type": "markdown", 
          "metadata": {}, 
          "source": [
            "\n\n", 
            "In addition to all this information, the dataset also carries a key\nattribute: the ", 
            "*mapper*. A mapper is an important concept in PyMVPA, and\nhence worth devoting the whole ", 
            "*next tutorial chapter* to it."
          ]
        }, 
        {
          "cell_type": "code", 
          "collapsed": false, 
          "input": [
            "print ds.a.mapper"
          ], 
          "language": "python", 
          "metadata": {}, 
          "outputs": []
        }, 
        {
          "cell_type": "markdown", 
          "metadata": {}, 
          "source": [
            "\n\n", 
            "Having all these attributes being part of a dataset is often a useful thing\nto have, but in some cases (e.g. when it comes to efficiency, and/or very\nlarge datasets) one might want to have a leaner dataset with just the\ninformation that is really necessary. One way to achieve this, is to strip\nall unwanted attributes. The Dataset class'\n", 
            "[AttrDataset.copy()](http://pymvpa.org/generated/mvpa2.base.dataset.AttrDataset.html#mvpa2.base.dataset.AttrDataset.copy) method can help with that."
          ]
        }, 
        {
          "cell_type": "code", 
          "collapsed": false, 
          "input": [
            "stripped = ds.copy(deep=False, sa=['time_coords'], fa=[], a=[])\n", 
            "print stripped"
          ], 
          "language": "python", 
          "metadata": {}, 
          "outputs": []
        }, 
        {
          "cell_type": "markdown", 
          "metadata": {}, 
          "source": [
            "\n\n", 
            "We can see that all attributes besides `time_coords` have been filtered out.\nSetting the `deep` arguments to `False` causes the copy function to reuse the\ndata from the source dataset to generate the new stripped one, without\nduplicating all data in memory -- meaning both datasets now share the sample\ndata and any change done to `ds` will also affect `stripped`."
          ]
        }, 
        {
          "cell_type": "heading", 
          "level": 2, 
          "metadata": {}, 
          "source": [
            "Storage"
          ]
        }, 
        {
          "cell_type": "markdown", 
          "metadata": {}, 
          "source": [
            "\n\n", 
            "Some data preprocessing can take a long time.  One would rather prevent\ndoing it over and over again, and instead just store the preprocessed data\ninto a file for subsequent analyses. PyMVPA offers functionality to store a\nlarge variety of objects, including datasets, into ", 
            "[HDF5][HDF5] files. A variant\nof this format is also used by recent versions of Matlab to store data.\n\n", 
            "For HDF5 support PyMVPA depends on the ", 
            "[h5py][h5py] package. If it is available,\nany dataset can be saved to a file by simply calling\n", 
            "[AttrDataset.save()](http://pymvpa.org/generated/mvpa2.base.dataset.AttrDataset.html#mvpa2.base.dataset.AttrDataset.save) with the desired filename."
          ]
        }, 
        {
          "cell_type": "code", 
          "collapsed": false, 
          "input": [
            "import tempfile, shutil\n", 
            "tempdir = tempfile.mkdtemp()\n", 
            "ds.save(os.path.join(tempdir, 'mydataset.hdf5'))"
          ], 
          "language": "python", 
          "metadata": {}, 
          "outputs": []
        }, 
        {
          "cell_type": "markdown", 
          "metadata": {}, 
          "source": [
            "\n\n", 
            "HDF5 is a flexible format that also supports, for example, data\ncompression. To enable it, you can pass additional arguments to\n", 
            "[AttrDataset.save()](http://pymvpa.org/generated/mvpa2.base.dataset.AttrDataset.html#mvpa2.base.dataset.AttrDataset.save) that are supported by\n", 
            "`Group.create_dataset()`. Instead of using\n", 
            "[AttrDataset.save()](http://pymvpa.org/generated/mvpa2.base.dataset.AttrDataset.html#mvpa2.base.dataset.AttrDataset.save) one can also use the ", 
            "[h5save()](http://pymvpa.org/generated/mvpa2.base.hdf5.h5save.html#mvpa2-base-hdf5-h5save)\nfunction in a similar way. Saving the same dataset with maximum\ngzip-compression looks like this:"
          ]
        }, 
        {
          "cell_type": "code", 
          "collapsed": false, 
          "input": [
            "ds.save(os.path.join(tempdir, 'mydataset.gzipped.hdf5'), compression=9)\n", 
            "h5save(os.path.join(tempdir, 'mydataset.gzipped.hdf5'), ds, compression=9)"
          ], 
          "language": "python", 
          "metadata": {}, 
          "outputs": []
        }, 
        {
          "cell_type": "markdown", 
          "metadata": {}, 
          "source": [
            "\n\n", 
            "Loading datasets from a file is easy too. ", 
            "[h5load()](http://pymvpa.org/generated/mvpa2.base.hdf5.h5load.html#mvpa2-base-hdf5-h5load) takes a filename as\nan argument and returns the stored dataset. Compressed data will be handled\ntransparently."
          ]
        }, 
        {
          "cell_type": "code", 
          "collapsed": false, 
          "input": [
            "loaded = h5load(os.path.join(tempdir, 'mydataset.hdf5'))\n", 
            "np.all(ds.samples == loaded.samples)"
          ], 
          "language": "python", 
          "metadata": {}, 
          "outputs": []
        }, 
        {
          "cell_type": "code", 
          "collapsed": false, 
          "input": [
            "shutil.rmtree(tempdir, ignore_errors=True)"
          ], 
          "language": "python", 
          "metadata": {}, 
          "outputs": []
        }
      ], 
      "metadata": {}
    }
  ]
}
.. @+node:ekr.20121005105428.10095: *4* << ipynb example >>
# s = '["foo", {"bar":["baz", null, 1.0, 2]}]'

s = '''
{
  "metadata": {
    "name": "Part 2: Dataset Basics and Concepts"
  }, 
  "nbformat": 3, 
  "nbformat_minor": 0, 
  "worksheets": [
    {
      "cells": [
        {
          "cell_type": "heading", 
          "level": 1, 
          "metadata": {}, 
          "source": [
            "Part 2: Dataset Basics and Concepts"
          ]
        }
      ]
    }
  ]
}
'''

s2 = '''
        {
          "cell_type": "markdown", 
          "metadata": {}, 
          "source": [
            "- - -\n*Note*", 
            "\n\n", 
            "This tutorial part is also available for download as an ", 
            "[IPython notebook][IPython notebook]:\n[", 
            "[ipynb][ipynb]]", 
            "- - -\n"
          ]
        }, 
        {
          "cell_type": "markdown", 
          "metadata": {}, 
          "source": [
            "\n\n", 
            "A ", 
            "[Dataset](http://pymvpa.org/generated/mvpa2.datasets.base.Dataset.html#mvpa2-datasets-base-dataset) is the basic data container in PyMVPA. It\nserves as the primary form of input data storage, but also as container for\nmore complex results returned by some algorithm. In this tutorial part we will\ntake a look at what a dataset consists of, and how it works.\n\n", 
            "In the simplest case, a dataset only contains ", 
            "*data* that is a matrix of\nnumerical values."
          ]
        }, 
        {
          "cell_type": "code", 
          "collapsed": false, 
          "input": [
            "from mvpa2.tutorial_suite import *\n", 
            "data = [[  1,  1, -1],\n        [  2,  0,  0],\n        [  3,  1,  1],\n        [  4,  0, -1]]\n", 
            "ds = Dataset(data)\n", 
            "ds.shape"
          ], 
          "language": "python", 
          "metadata": {}, 
          "outputs": []
        }, 
        {
          "cell_type": "code", 
          "collapsed": false, 
          "input": [
            "len(ds)"
          ], 
          "language": "python", 
          "metadata": {}, 
          "outputs": []
        }, 
        {
          "cell_type": "code", 
          "collapsed": false, 
          "input": [
            "ds.nfeatures"
          ], 
          "language": "python", 
          "metadata": {}, 
          "outputs": []
        }, 
        {
          "cell_type": "code", 
          "collapsed": false, 
          "input": [
            "ds.samples"
          ], 
          "language": "python", 
          "metadata": {}, 
          "outputs": []
        }, 
        {
          "cell_type": "markdown", 
          "metadata": {}, 
          "source": [
            "\n\n", 
            "In the above example, every row vector in the `data` matrix becomes an\nobservation or a ", 
            "[sample](http://pymvpa.org/glossary.html#term-sample) in the dataset, and every column vector\nrepresents an individual variable or a ", 
            "[feature](http://pymvpa.org/glossary.html#term-feature). The concepts of samples\nand features are essential for a dataset, hence we take a further, closer look.\n\n", 
            "The dataset assumes the first axis of the data to be the samples separating\ndimension. If the dataset is created using a one-dimensional vector it will\ntherefore have as many samples as elements in the vector, and only one feature."
          ]
        }, 
        {
          "cell_type": "code", 
          "collapsed": false, 
          "input": [
            "one_d = [ 0, 1, 2, 3 ]\n", 
            "one_ds = Dataset(one_d)\n", 
            "one_ds.shape"
          ], 
          "language": "python", 
          "metadata": {}, 
          "outputs": []
        }, 
        {
          "cell_type": "markdown", 
          "metadata": {}, 
          "source": [
            "\n\n", 
            "On the other hand, if a dataset is created from multi-dimensional data, only its\nsecond axis represents the features"
          ]
        }, 
        {
          "cell_type": "code", 
          "collapsed": false, 
          "input": [
            "import numpy as np\n", 
            "m_ds = Dataset(np.random.random((3, 4, 2, 3)))\n", 
            "m_ds.shape"
          ], 
          "language": "python", 
          "metadata": {}, 
          "outputs": []
        }, 
        {
          "cell_type": "code", 
          "collapsed": false, 
          "input": [
            "m_ds.nfeatures"
          ], 
          "language": "python", 
          "metadata": {}, 
          "outputs": []
        }, 
        {
          "cell_type": "markdown", 
          "metadata": {}, 
          "source": [
            "\n\n", 
            "In this case we have a dataset with three samples and four features, where each\nfeature is a 2x3 matrix. In case somebody is wondering now, why not simply each\nvalue in the data array is considered as its own feature (yielding 24 features)\n-- stay tuned, as this is going to be of importance later on."
          ]
        }, 
        {
          "cell_type": "heading", 
          "level": 2, 
          "metadata": {}, 
          "source": [
            "Attributes"
          ]
        }, 
        {
          "cell_type": "markdown", 
          "metadata": {}, 
          "source": [
            "\n\n", 
            "What we have seen so far does not really warrant the use of a dataset over a\nplain array or a matrix with samples. However, in the MVPA context we often need\nto know more about each samples than just the value of its features.  In the\nprevious tutorial part we have already seen that per-sample ", 
            "[target](http://pymvpa.org/glossary.html#term-target)\nvalues are required for supervised-learning algorithms, and that a dataset\noften has to be split based on the origin of specific groups of samples.  For\nthis type of auxiliary information a dataset can also contain collections of\nthree types of ", 
            "[attribute](http://pymvpa.org/glossary.html#term-attribute)s: ", 
            "[sample attribute](http://pymvpa.org/glossary.html#term-sample-attribute), ", 
            "[feature attribute](http://pymvpa.org/glossary.html#term-feature-attribute), and\n", 
            "[dataset attribute](http://pymvpa.org/glossary.html#term-dataset-attribute)."
          ]
        }, 
        {
          "cell_type": "heading", 
          "level": 3, 
          "metadata": {}, 
          "source": [
            "For Samples"
          ]
        }, 
        {
          "cell_type": "markdown", 
          "metadata": {}, 
          "source": [
            "\n\n", 
            "In a dataset each ", 
            "[sample](http://pymvpa.org/glossary.html#term-sample) can have an arbitrary number of additional\nattributes. They are stored as vectors of the same length as the number of samples\nin a collection, and are accessible via the `sa` attribute. A collection is\nderived from a standard Python ", 
            "`dict`, and hence adding sample attributes\nworks identical to adding elements to a dictionary:"
          ]
        }, 
        {
          "cell_type": "code", 
          "collapsed": false, 
          "input": [
            "ds.sa['some_attr'] = [ 0., 1, 1, 3 ]\n", 
            "ds.sa.keys()"
          ], 
          "language": "python", 
          "metadata": {}, 
          "outputs": []
        }, 
        {
          "cell_type": "markdown", 
          "metadata": {}, 
          "source": [
            "\n\n", 
            "However, sample attributes are not directly stored as plain data, but for\nvarious reasons as a so-called ", 
            "[Collectable](http://pymvpa.org/generated/mvpa2.base.collections.Collectable.html#mvpa2-base-collections-collectable) that in\nturn embeds a NumPy array with the actual attribute:"
          ]
        }, 
        {
          "cell_type": "code", 
          "collapsed": false, 
          "input": [
            "type(ds.sa['some_attr'])"
          ], 
          "language": "python", 
          "metadata": {}, 
          "outputs": []
        }, 
        {
          "cell_type": "code", 
          "collapsed": false, 
          "input": [
            "ds.sa['some_attr'].value"
          ], 
          "language": "python", 
          "metadata": {}, 
          "outputs": []
        }, 
        {
          "cell_type": "markdown", 
          "metadata": {}, 
          "source": [
            "\n\n", 
            "This \"complication\" is done to be able to extend attributes with additional\nfunctionality that is often needed and can offer significant speed-up of\nprocessing. For example, sample attributes carry a list of their unique values.\nThis list is only computed once (upon first request) and can subsequently be\naccessed directly without repeated and expensive searches:"
          ]
        }, 
        {
          "cell_type": "code", 
          "collapsed": false, 
          "input": [
            "ds.sa['some_attr'].unique"
          ], 
          "language": "python", 
          "metadata": {}, 
          "outputs": []
        }, 
        {
          "cell_type": "markdown", 
          "metadata": {}, 
          "source": [
            "\n\n", 
            "However, for most interactive uses of PyMVPA this type of access to attributes'\n`.value` is relatively cumbersome (too much typing), therefore collections offer direct\nattribute access by name:"
          ]
        }, 
        {
          "cell_type": "code", 
          "collapsed": false, 
          "input": [
            "ds.sa.some_attr"
          ], 
          "language": "python", 
          "metadata": {}, 
          "outputs": []
        }, 
        {
          "cell_type": "markdown", 
          "metadata": {}, 
          "source": [
            "\n\n", 
            "Another purpose of the sample attribute collection is to preserve data\nintegrity, by disallowing improper attributes:"
          ]
        }, 
        {
          "cell_type": "code", 
          "collapsed": false, 
          "input": [
            "ds.sa['invalid'] = 4"
          ], 
          "language": "python", 
          "metadata": {}, 
          "outputs": []
        }, 
        {
          "cell_type": "code", 
          "collapsed": false, 
          "input": [
            "ds.sa['invalid'] = [ 1, 2, 3, 4, 5, 6 ]"
          ], 
          "language": "python", 
          "metadata": {}, 
          "outputs": []
        }, 
        {
          "cell_type": "markdown", 
          "metadata": {}, 
          "source": [
            "\n\n", 
            "But other than basic plausibility checks no further constraints on values of\nsamples attributes exist. As long as the length of the attribute vector matches\nthe number of samples in the dataset, and the attributes values can be stored\nin a NumPy array, any value is allowed. For example, it is perfectly possible\nand supported to store literal attributes. It should also be noted that each\nattribute may have its own individual data type, hence it is possible to have\nliteral and numeric attributes in the same dataset."
          ]
        }, 
        {
          "cell_type": "code", 
          "collapsed": false, 
          "input": [
            "ds.sa['literal'] = ['one', 'two', 'three', 'four']\n", 
            "sorted(ds.sa.keys())"
          ], 
          "language": "python", 
          "metadata": {}, 
          "outputs": []
        }, 
        {
          "cell_type": "code", 
          "collapsed": false, 
          "input": [
            "for attr in ds.sa:\n   print \"%s: %s\" % (attr, ds.sa[attr].value.dtype.name)"
          ], 
          "language": "python", 
          "metadata": {}, 
          "outputs": []
        }, 
        {
          "cell_type": "heading", 
          "level": 3, 
          "metadata": {}, 
          "source": [
            "For Features"
          ]
        }, 
        {
          "cell_type": "markdown", 
          "metadata": {}, 
          "source": [
            "\n\n", 
            "[Feature attribute](http://pymvpa.org/glossary.html#term-feature-attribute)s are almost identical to ", 
            "[sample attribute](http://pymvpa.org/glossary.html#term-sample-attribute)s the ", 
            "*only* difference is that instead of having one attribute value per\nsample, feature attributes have one value per (guess what? ...) ", 
            "*feature*.\nMoreover, they are stored in a separate collection in the datasets that is\ncalled `fa`:"
          ]
        }, 
        {
          "cell_type": "code", 
          "collapsed": false, 
          "input": [
            "ds.nfeatures"
          ], 
          "language": "python", 
          "metadata": {}, 
          "outputs": []
        }, 
        {
          "cell_type": "code", 
          "collapsed": false, 
          "input": [
            "ds.fa['my_fav'] = [0, 1, 0]\n", 
            "ds.fa['responsible'] = ['me', 'you', 'nobody']\n", 
            "sorted(ds.fa.keys())"
          ], 
          "language": "python", 
          "metadata": {}, 
          "outputs": []
        }, 
        {
          "cell_type": "heading", 
          "level": 3, 
          "metadata": {}, 
          "source": [
            "For The Dataset"
          ]
        }, 
        {
          "cell_type": "markdown", 
          "metadata": {}, 
          "source": [
            "\n\n", 
            "Finally, there can be also attributes, not per each sample, or each\nfeature, but for the dataset as a whole: so called ", 
            "[dataset](http://pymvpa.org/glossary.html#term-dataset)s. Assigning such attributes and accessing them later on work in\nexactly the same way as for the other two types of attributes, except that dataset\nattributes are stored in their own collection which is accessible via the\n`a` property of the dataset.  However, in contrast to sample and feature\nattribute no constraints on the type or size are imposed -- anything can be\nstored. Let's store a list with all files in the current directory, just\nbecause we can:"
          ]
        }, 
        {
          "cell_type": "code", 
          "collapsed": false, 
          "input": [
            "from glob import glob\n", 
            "ds.a['pointless'] = glob(\"*\")\n", 
            "'setup.py' in ds.a.pointless"
          ], 
          "language": "python", 
          "metadata": {}, 
          "outputs": []
        }, 
        {
          "cell_type": "heading", 
          "level": 2, 
          "metadata": {}, 
          "source": [
            "Slicing, resampling, feature selection"
          ]
        }, 
        {
          "cell_type": "markdown", 
          "metadata": {}, 
          "source": [
            "\n\n", 
            "At this point we can already construct a dataset from simple arrays and\nenrich it with an arbitrary number of additional attributes. But just\nhaving a dataset isn't enough. From part one of this tutorial we already\nknow that we need to be able to select subsets of a dataset for further\nprocessing, and we also know that this is possible with PyMVPA's datasets.\nNow it is time to have a closer look into how it works.\n\n", 
            "Slicing a dataset (i.e. selecting specific subsets) is very similar to\nslicing a NumPy array. It actually works ", 
            "*almost* identical. A dataset\nsupports Python's ", 
            "`slice` syntax, but also selection by boolean masks, and\nindices. The following three slicing operations\nresult in equivalent output datasets, by always selecting every other samples\nin the dataset:"
          ]
        }, 
        {
          "cell_type": "code", 
          "collapsed": false, 
          "input": [
            "ds.samples"
          ], 
          "language": "python", 
          "metadata": {}, 
          "outputs": []
        }, 
        {
          "cell_type": "code", 
          "collapsed": false, 
          "input": [
            "ds[::2].samples"
          ], 
          "language": "python", 
          "metadata": {}, 
          "outputs": []
        }, 
        {
          "cell_type": "code", 
          "collapsed": false, 
          "input": [
            "mask = np.array([True, False, True, False])\n", 
            "ds[mask].samples"
          ], 
          "language": "python", 
          "metadata": {}, 
          "outputs": []
        }, 
        {
          "cell_type": "code", 
          "collapsed": false, 
          "input": [
            "ds[[0, 2]].samples"
          ], 
          "language": "python", 
          "metadata": {}, 
          "outputs": []
        }, 
        {
          "cell_type": "markdown", 
          "metadata": {}, 
          "source": [
            "- - -\n*Exercise*", 
            "\n\n", 
            "Search the `NumPy documentation`_ for the difference between \"basic slicing\"\nand \"advanced indexing\". Especially the aspect of memory consumption\napplies to dataset slicing as well, and being aware of this fact might\nhelp to write more efficient analysis scripts. Which of the three slicing\napproaches above is the most memory-efficient?  Which of the three slicing\napproaches above might lead to unexpected side-effects if output dataset\ngets modified?"
          ]
        }, 
        {
          "cell_type": "code", 
          "collapsed": false, 
          "input": [
            "# you can use this cell to for this exercise"
          ], 
          "language": "python", 
          "metadata": {}, 
          "outputs": []
        }, 
        {
          "cell_type": "markdown", 
          "metadata": {}, 
          "source": [
            "- - -\n", 
            "\n\n", 
            "All three slicing-styles are equally applicable to the selection of feature\nsubsets within a dataset. Remember, features are represented on the second axis\nof a dataset."
          ]
        }, 
        {
          "cell_type": "code", 
          "collapsed": false, 
          "input": [
            "ds[:, [1,2]].samples"
          ], 
          "language": "python", 
          "metadata": {}, 
          "outputs": []
        }, 
        {
          "cell_type": "markdown", 
          "metadata": {}, 
          "source": [
            "\n\n", 
            "By applying a selection by indices to the second axis, we can easily get\nthe last two features of our example dataset. Please note the ", 
            "`:` is supplied\nas first axis slicing. This is the Python way to indicate ", 
            "*take everything\nalong this axis*, hence including all samples.\n\n", 
            "As you can guess, it is also possible to select subsets of samples and\nfeatures at the same time."
          ]
        }, 
        {
          "cell_type": "code", 
          "collapsed": false, 
          "input": [
            "subds = ds[[0,1], [0,2]]\n", 
            "subds.samples"
          ], 
          "language": "python", 
          "metadata": {}, 
          "outputs": []
        }, 
        {
          "cell_type": "markdown", 
          "metadata": {}, 
          "source": [
            "\n\n", 
            "If you have prior experience with NumPy you might be confused now. What you\nmight have expected is this:"
          ]
        }, 
        {
          "cell_type": "code", 
          "collapsed": false, 
          "input": [
            "ds.samples[[0,1], [0,2]]"
          ], 
          "language": "python", 
          "metadata": {}, 
          "outputs": []
        }, 
        {
          "cell_type": "markdown", 
          "metadata": {}, 
          "source": [
            "\n\n", 
            "The above code applies the same slicing directly to the NumPy array with\nthe samples, and the result is fundamentally different. For NumPy arrays\nthis style of slicing allows to select specific elements by their indices on\neach axis of an array. For PyMVPA's datasets this mode is not very useful,\ninstead we typically want to select rows and columns, i.e. samples and\nfeatures given by their indices."
          ]
        }, 
        {
          "cell_type": "markdown", 
          "metadata": {}, 
          "source": [
            "- - -\n*Exercise*", 
            "\n\n", 
            "Try to select samples [0,1] and features [0,2,3] simultaneously using\ndataset slicing.  Now apply the same slicing to the samples array itself\n(`ds.samples`) -- make sure that the result doesn't surprise you and find\na pure NumPy way to achieve similar selection."
          ]
        }, 
        {
          "cell_type": "code", 
          "collapsed": false, 
          "input": [
            "# you can use this cell to for this exercise"
          ], 
          "language": "python", 
          "metadata": {}, 
          "outputs": []
        }, 
        {
          "cell_type": "markdown", 
          "metadata": {}, 
          "source": [
            "- - -\n", 
            "\n\n", 
            "One last interesting thing to look at, in the context of dataset slicing\nare the attributes. What happens to them when a subset of samples and/or\nfeatures is chosen? Our original dataset had both samples and feature attributes:"
          ]
        }, 
        {
          "cell_type": "code", 
          "collapsed": false, 
          "input": [
            "print ds.sa.some_attr"
          ], 
          "language": "python", 
          "metadata": {}, 
          "outputs": []
        }, 
        {
          "cell_type": "code", 
          "collapsed": false, 
          "input": [
            "print ds.fa.responsible"
          ], 
          "language": "python", 
          "metadata": {}, 
          "outputs": []
        }, 
        {
          "cell_type": "markdown", 
          "metadata": {}, 
          "source": [
            "\n\n", 
            "Now let's look at what they became in the subset-dataset we previously\ncreated:"
          ]
        }, 
        {
          "cell_type": "code", 
          "collapsed": false, 
          "input": [
            "print subds.sa.some_attr"
          ], 
          "language": "python", 
          "metadata": {}, 
          "outputs": []
        }, 
        {
          "cell_type": "code", 
          "collapsed": false, 
          "input": [
            "print subds.fa.responsible"
          ], 
          "language": "python", 
          "metadata": {}, 
          "outputs": []
        }, 
        {
          "cell_type": "markdown", 
          "metadata": {}, 
          "source": [
            "\n\n", 
            "We see that both attributes are still there and, moreover, also the\nappropriate subsets have been selected."
          ]
        }, 
        {
          "cell_type": "heading", 
          "level": 2, 
          "metadata": {}, 
          "source": [
            "Loading fMRI data"
          ]
        }, 
        {
          "cell_type": "markdown", 
          "metadata": {}, 
          "source": [
            "\n\n", 
            "Enough of theoretical foreplay -- let's look at a concrete example of an\nfMRI dataset. PyMVPA has several helper functions to load data from\nspecialized formats, and the one for fMRI data is\n", 
            "[fmri_dataset()](http://pymvpa.org/generated/mvpa2.datasets.mri.fmri_dataset.html#mvpa2-datasets-mri-fmri-dataset). The example dataset we are going to\nlook at is a single subject from Haxby et al. (2001) that we already\nloaded in part one of this tutorial. For more convenience, and less typing\nwe first specify the path of the directory with the fMRI data."
          ]
        }, 
        {
          "cell_type": "code", 
          "collapsed": false, 
          "input": [
            "path=os.path.join(tutorial_data_path, 'data')"
          ], 
          "language": "python", 
          "metadata": {}, 
          "outputs": []
        }, 
        {
          "cell_type": "markdown", 
          "metadata": {}, 
          "source": [
            "\n\n", 
            "In the simplest case, we now let ", 
            "[fmri_dataset](http://pymvpa.org/generated/mvpa2.datasets.mri.fmri_dataset.html#mvpa2-datasets-mri-fmri-dataset) do its job, by just\npointing it to the fMRI data file. The data is stored as a NIfTI file that has\nall runs of the experiment concatenated into a single file."
          ]
        }, 
        {
          "cell_type": "code", 
          "collapsed": false, 
          "input": [
            "ds = fmri_dataset(os.path.join(path, 'bold.nii.gz'))\n", 
            "len(ds)"
          ], 
          "language": "python", 
          "metadata": {}, 
          "outputs": []
        }, 
        {
          "cell_type": "code", 
          "collapsed": false, 
          "input": [
            "ds.nfeatures"
          ], 
          "language": "python", 
          "metadata": {}, 
          "outputs": []
        }, 
        {
          "cell_type": "code", 
          "collapsed": false, 
          "input": [
            "ds.shape"
          ], 
          "language": "python", 
          "metadata": {}, 
          "outputs": []
        }, 
        {
          "cell_type": "markdown", 
          "metadata": {}, 
          "source": [
            "\n\n", 
            "We can notice two things. First, it worked! Second, we get a\ntwo-dimensional dataset with 1452 samples (these are volumes in the NIfTI\nfile), and over 160k features (these are voxels in the volume). The voxels\nare represented as a one-dimensional vector, and it seems that they have\nlost their association with the 3D-voxel-space. However, this is not the\ncase, as we will see in the next chapter.  PyMVPA represents\ndata in this simple format to make it compatible with a vast range of generic\nalgorithms that expect data to be a simple matrix.\n\n", 
            "We just loaded all data from that NIfTI file, but usually we would be\ninterested in a subset only, i.e. \"brain voxels\".\n", 
            "[fmri_dataset](http://pymvpa.org/generated/mvpa2.datasets.mri.fmri_dataset.html#mvpa2-datasets-mri-fmri-dataset) is capable of performing data masking. We just need to\nspecify a mask image. Such mask image is generated in pretty much any fMRI\nanalysis pipeline -- may it be a full-brain mask computed during\nskull-stripping, or an activation map from a functional localizer. We are going\nto use the original GLM-based localizer mask of ventral temporal cortex\nfrom Haxby et al. (2001). We already know that it comprises 577 voxels.\nLet's reload the dataset:"
          ]
        }, 
        {
          "cell_type": "code", 
          "collapsed": false, 
          "input": [
            "ds = fmri_dataset(os.path.join(path, 'bold.nii.gz'),\n                  mask=os.path.join(path, 'mask_vt.nii.gz'))\n", 
            "len(ds)"
          ], 
          "language": "python", 
          "metadata": {}, 
          "outputs": []
        }, 
        {
          "cell_type": "code", 
          "collapsed": false, 
          "input": [
            "ds.nfeatures"
          ], 
          "language": "python", 
          "metadata": {}, 
          "outputs": []
        }, 
        {
          "cell_type": "markdown", 
          "metadata": {}, 
          "source": [
            "\n\n", 
            "As expected, we get the same number of samples and also only 577 features\n-- voxels corresponding to non-zero elements in the mask image. Now, let's\nexplore this dataset a little further.\n\n", 
            "Besides samples the dataset offers number of attributes that enhance the\ndata with information that is present in the NIfTI image header in the file. Each sample has\ninformation about its volume ID in the time series and the actual acquisition\ntime (relative to the beginning of the file). Moreover, the original voxel\nindex (sometimes referred to as `ijk`) for each feature is available too.\nFinally, the dataset also contains information about the dimensionality\nof the input volumes, voxel size, and any other NIfTI-specific information\nsince it also includes a dump of the full NIfTI image header."
          ]
        }, 
        {
          "cell_type": "markdown", 
          "metadata": {}, 
          "source": [
            "- - -\n*Note*", 
            "\n\n", 
            "Previously (0.4.x versions and 0.5 development prior March 03, 2010),\nPyMVPA exposed 4D (and 3D with degenerate 1st dimension) data in `tkji`\n(corresponds to `tzyx` if volumes were axial slices in\nneurologic convention) order of dimensions.  Now it uses more convenient\norder `tijk` (corresponding to `txyz`), which will match the order exposed\nby NiBabel (PyNIfTI and NiftiImage still expose them as `tkji`).", 
            "- - -\n"
          ]
        }, 
        {
          "cell_type": "code", 
          "collapsed": false, 
          "input": [
            "ds.sa.time_indices[:5]"
          ], 
          "language": "python", 
          "metadata": {}, 
          "outputs": []
        }, 
        {
          "cell_type": "code", 
          "collapsed": false, 
          "input": [
            "ds.sa.time_coords[:5]"
          ], 
          "language": "python", 
          "metadata": {}, 
          "outputs": []
        }, 
        {
          "cell_type": "code", 
          "collapsed": false, 
          "input": [
            "ds.fa.voxel_indices[:5]"
          ], 
          "language": "python", 
          "metadata": {}, 
          "outputs": []
        }, 
        {
          "cell_type": "code", 
          "collapsed": false, 
          "input": [
            "ds.a.voxel_eldim"
          ], 
          "language": "python", 
          "metadata": {}, 
          "outputs": []
        }, 
        {
          "cell_type": "code", 
          "collapsed": false, 
          "input": [
            "ds.a.voxel_dim"
          ], 
          "language": "python", 
          "metadata": {}, 
          "outputs": []
        }, 
        {
          "cell_type": "code", 
          "collapsed": false, 
          "input": [
            "'imghdr' in ds.a"
          ], 
          "language": "python", 
          "metadata": {}, 
          "outputs": []
        }, 
        {
          "cell_type": "markdown", 
          "metadata": {}, 
          "source": [
            "\n\n", 
            "In addition to all this information, the dataset also carries a key\nattribute: the ", 
            "*mapper*. A mapper is an important concept in PyMVPA, and\nhence worth devoting the whole ", 
            "*next tutorial chapter* to it."
          ]
        }, 
        {
          "cell_type": "code", 
          "collapsed": false, 
          "input": [
            "print ds.a.mapper"
          ], 
          "language": "python", 
          "metadata": {}, 
          "outputs": []
        }, 
        {
          "cell_type": "markdown", 
          "metadata": {}, 
          "source": [
            "\n\n", 
            "Having all these attributes being part of a dataset is often a useful thing\nto have, but in some cases (e.g. when it comes to efficiency, and/or very\nlarge datasets) one might want to have a leaner dataset with just the\ninformation that is really necessary. One way to achieve this, is to strip\nall unwanted attributes. The Dataset class'\n", 
            "[AttrDataset.copy()](http://pymvpa.org/generated/mvpa2.base.dataset.AttrDataset.html#mvpa2.base.dataset.AttrDataset.copy) method can help with that."
          ]
        }, 
        {
          "cell_type": "code", 
          "collapsed": false, 
          "input": [
            "stripped = ds.copy(deep=False, sa=['time_coords'], fa=[], a=[])\n", 
            "print stripped"
          ], 
          "language": "python", 
          "metadata": {}, 
          "outputs": []
        }, 
        {
          "cell_type": "markdown", 
          "metadata": {}, 
          "source": [
            "\n\n", 
            "We can see that all attributes besides `time_coords` have been filtered out.\nSetting the `deep` arguments to `False` causes the copy function to reuse the\ndata from the source dataset to generate the new stripped one, without\nduplicating all data in memory -- meaning both datasets now share the sample\ndata and any change done to `ds` will also affect `stripped`."
          ]
        }, 
        {
          "cell_type": "heading", 
          "level": 2, 
          "metadata": {}, 
          "source": [
            "Storage"
          ]
        }, 
        {
          "cell_type": "markdown", 
          "metadata": {}, 
          "source": [
            "\n\n", 
            "Some data preprocessing can take a long time.  One would rather prevent\ndoing it over and over again, and instead just store the preprocessed data\ninto a file for subsequent analyses. PyMVPA offers functionality to store a\nlarge variety of objects, including datasets, into ", 
            "[HDF5][HDF5] files. A variant\nof this format is also used by recent versions of Matlab to store data.\n\n", 
            "For HDF5 support PyMVPA depends on the ", 
            "[h5py][h5py] package. If it is available,\nany dataset can be saved to a file by simply calling\n", 
            "[AttrDataset.save()](http://pymvpa.org/generated/mvpa2.base.dataset.AttrDataset.html#mvpa2.base.dataset.AttrDataset.save) with the desired filename."
          ]
        }, 
        {
          "cell_type": "code", 
          "collapsed": false, 
          "input": [
            "import tempfile, shutil\n", 
            "tempdir = tempfile.mkdtemp()\n", 
            "ds.save(os.path.join(tempdir, 'mydataset.hdf5'))"
          ], 
          "language": "python", 
          "metadata": {}, 
          "outputs": []
        }, 
        {
          "cell_type": "markdown", 
          "metadata": {}, 
          "source": [
            "\n\n", 
            "HDF5 is a flexible format that also supports, for example, data\ncompression. To enable it, you can pass additional arguments to\n", 
            "[AttrDataset.save()](http://pymvpa.org/generated/mvpa2.base.dataset.AttrDataset.html#mvpa2.base.dataset.AttrDataset.save) that are supported by\n", 
            "`Group.create_dataset()`. Instead of using\n", 
            "[AttrDataset.save()](http://pymvpa.org/generated/mvpa2.base.dataset.AttrDataset.html#mvpa2.base.dataset.AttrDataset.save) one can also use the ", 
            "[h5save()](http://pymvpa.org/generated/mvpa2.base.hdf5.h5save.html#mvpa2-base-hdf5-h5save)\nfunction in a similar way. Saving the same dataset with maximum\ngzip-compression looks like this:"
          ]
        }, 
        {
          "cell_type": "code", 
          "collapsed": false, 
          "input": [
            "ds.save(os.path.join(tempdir, 'mydataset.gzipped.hdf5'), compression=9)\n", 
            "h5save(os.path.join(tempdir, 'mydataset.gzipped.hdf5'), ds, compression=9)"
          ], 
          "language": "python", 
          "metadata": {}, 
          "outputs": []
        }, 
        {
          "cell_type": "markdown", 
          "metadata": {}, 
          "source": [
            "\n\n", 
            "Loading datasets from a file is easy too. ", 
            "[h5load()](http://pymvpa.org/generated/mvpa2.base.hdf5.h5load.html#mvpa2-base-hdf5-h5load) takes a filename as\nan argument and returns the stored dataset. Compressed data will be handled\ntransparently."
          ]
        }, 
        {
          "cell_type": "code", 
          "collapsed": false, 
          "input": [
            "loaded = h5load(os.path.join(tempdir, 'mydataset.hdf5'))\n", 
            "np.all(ds.samples == loaded.samples)"
          ], 
          "language": "python", 
          "metadata": {}, 
          "outputs": []
        }, 
        {
          "cell_type": "code", 
          "collapsed": false, 
          "input": [
            "shutil.rmtree(tempdir, ignore_errors=True)"
          ], 
          "language": "python", 
          "metadata": {}, 
          "outputs": []
        }
      ], 
      "metadata": {}
    }
  ]
}
'''
.. @+node:ekr.20121005105428.10109: *4* JSON Reference
if 0:
    @others
.. @+node:ekr.20121005105428.10102: *5* class NoteBookReader
class NotebookReader(object): # From rwbase.py
    """A class for reading notebooks."""

    def reads(self, s, **kwargs):
        """Read a notebook from a string."""
        raise NotImplementedError("loads must be implemented in a subclass")

    def read(self, fp, **kwargs):
        """Read a notebook from a file like object"""
        nbs = fp.read()
        if not py3compat.PY3 and not isinstance(nbs, unicode):
            nbs = py3compat.str_to_unicode(nbs)
        return self.reads(nbs, **kwargs)
.. @+node:ekr.20121005105428.10108: *5* JSONReader(NotebookReader)
class JSONReader(NotebookReader):

    def reads(self, s, **kwargs):
        nb = json.loads(s, **kwargs)
        nb = self.to_notebook(nb, **kwargs)
        return nb

    def to_notebook(self, d, **kwargs):
        return restore_bytes(
            rejoin_lines(from_dict(d))) # from_dict and rejoin_lines are in nbbase.
.. @+node:ekr.20121005105428.10107: *5* class BytesEncoder
class BytesEncoder(json.JSONEncoder):
    """A JSON encoder that accepts b64 (and other *ascii*) bytestrings."""
    def default(self, obj):
        if isinstance(obj, bytes):
            return obj.decode('ascii')
        return json.JSONEncoder.default(self, obj)

.. @+node:ekr.20121005105428.10097: *5* From v3/nbjson.py
_reader = JSONReader()
reads = _reader.reads
read =  _reader.read
to_notebook = _reader.to_notebook
.. @+node:ekr.20121005105428.10098: *5* From v3/rwbase.py
.. @+node:ekr.20121005105428.10103: *6* fromDict
def from_dict(d):
    if isinstance(d, dict):
        newd = NotebookNode()
        for k,v in d.items():
            newd[k] = from_dict(v)
        return newd
    elif isinstance(d, (tuple, list)):
        return [from_dict(i) for i in d]
    else:
        return d
.. @+node:ekr.20121005105428.10104: *6* restore_bytes
def restore_bytes(nb):
    """Restore bytes of image data from unicode-only formats.
    
    Base64 encoding is handled elsewhere.  Bytes objects in the notebook are
    always b64-encoded. We DO NOT encode/decode around file formats.
    """
    for ws in nb.worksheets:
        for cell in ws.cells:
            if cell.cell_type == 'code':
                for output in cell.outputs:
                    if 'png' in output:
                        output.png = str_to_bytes(output.png, 'ascii')
                    if 'jpeg' in output:
                        output.jpeg = str_to_bytes(output.jpeg, 'ascii')
    return nb
.. @+node:ekr.20121005105428.10105: *6* _join_lines
def _join_lines(lines):
    """join lines that have been written by splitlines()
    
    Has logic to protect against `splitlines()`, which
    should have been `splitlines(True)`
    """
    if lines and lines[0].endswith(('\n', '\r')):
        # created by splitlines(True)
        return u''.join(lines)
    else:
        # created by splitlines()
        return u'\n'.join(lines)
.. @+node:ekr.20121005105428.10106: *6* rejoin_lines
def rejoin_lines(nb):
    """rejoin multiline text into strings
    
    For reversing effects of ``split_lines(nb)``.
    
    This only rejoins lines that have been split, so if text objects were not split
    they will pass through unchanged.
    
    Used when reading JSON files that may have been passed through split_lines.
    """
    for ws in nb.worksheets:
        for cell in ws.cells:
            if cell.cell_type == 'code':
                if 'input' in cell and isinstance(cell.input, list):
                    cell.input = _join_lines(cell.input)
                for output in cell.outputs:
                    for key in _multiline_outputs:
                        item = output.get(key, None)
                        if isinstance(item, list):
                            output[key] = _join_lines(item)
            else: # text, heading cell
                for key in ['source', 'rendered']:
                    item = cell.get(key, None)
                    if isinstance(item, list):
                        cell[key] = _join_lines(item)
    return nb
.. @+node:ekr.20121008100945.10295: *4* Installation notes for ipython 0.13
@nocolor-node

- Downloaded and ran ipython-0.13.py2-win32.exe
- Uninstalled several older IPython's using the Windows Control Panel

Linux
=====

- Installed pip: sudo apt-get install python-pip
- distribute was already installed in python2.7
- Installed curl: sudo apt-get install curl.
- Upgraded ipython: easy_install ipython[zmq,qtconsole,notebook,test] ipython==0.13
- Tested Ipython: iptest  Works!!!  not available:  oct2py rpy2
- removed home/.ipython/ipythonrc this removed the warnings on startup.

Windows:
========

- Download c:\apps\distribute_setup.py.
- python26 distribute_setup.py
- Removed all former versions of Enthought and ActiveState Python and IPython.
.. @+node:ekr.20120516140545.9991: *3* Maybe
.. @+node:ekr.20130807203905.16773: *4* Leo for portableapps?
.. @+node:ekr.20060227131611: *4* Kent: extensible auto-completion-like capabilities
@nocolor
http://sourceforge.net/forum/message.php?msg_id=3593116
By: ktenney

Zope3, with it's component based architecture,
has machinery which hooks components together ..
Interfaces, Adapters and ZCML, the configuration
language.

It sounds like the autocompleter code is able
to build indexes of classes and methods. It would
be cool if that capability could be extensible,
allowing building indexes of the couplings between
components.

I think this might look like some kind of automatic
hyperlinking, providing access to related code,
as defined for that application.

I really don't know if this makes sense, but
I see you moving in the direction of making Leo
capable of doing some _explaining_ of the code 
being written.
.. @+node:ekr.20120520113447.9874: *4* Kent: select node from traceback
@nocolor
http://sourceforge.net/forum/message.php?msg_id=3593116
By: ktenney

When I have a traceback in the log pane, I'd love
to be able to select an item and cause the file
to appear in a node.
It would be cool to have 'Next' and 'Prev' 
capability while in this mode, effortlessly 
traversing views of the source of the stack items.
.. @+node:ekr.20111028195854.16607: *4* Allow ruleset-specific colors
@nocolor-node

Like @color html::tags_markup_color = blue
.. @+node:ekr.20120322073519.10403: *4* Investigate solarized colors
The claim that Leo supports solarized has been withdrawn.

.. @+node:ekr.20120322073519.10405: *5* Added support for solarized colors
http://ethanschoonover.com/solarized

.. @+node:ekr.20130806072439.20430: *4* minor dabbrev improvements
was: Does dabbrev work?
From: "F.S." <speech.free@gmail.com>

The answer seems to be based on the exchange here:
https://groups.google.com/forum/?fromgroups=#!searchin/leo-editor/dabbrev/leo-editor/3A4JOHqhJSU/W1DjTvooNCkJ

Summary: Alt-/ always shows a completion list. Backspace works as expected:
showing more and more items.  Nothing needs to be done.

**Possible minor improvements**

In Emacs M-/ (dabbrev-expand) just expands to the first choice. You then
cycle through the choices by repeating M-/. If you go too far you can cycle
back with C-/. C-M-/ (dabbrev-completion) expands to the longest common
prefix.

With 5473: I seem to already get the behavior you are talking about: that on
M-/ I get a completion list. I agree that getting a list is nice, esp if
<backspace><tab> show more choices. (It does).


I think there are a few use cases here:
1) I know exactly what I want but I just don't want to type it again (I may 
be lazy or I don't want to create a typo) so give it to me with as few key 
strokes as possible
2) I am not quite sure so let me see the choices
3) None of the choices is what I need so let me go back and show me some 
more choices

Maybe a combination of behavior is the best. With M-/ and C-/ one just 
cycles through the choices (auto inserted), which takes care of 1). 
With C-M-/ (dabbrev-completion) one gets the longest prefix auto inserted 
and a list of choices. Now it would be truly great that if we can easily 
just <backspace><tab> to see potentially more choices. But how do you 
interface with both? For 2) one desires to type just one more letter so as 
to make a choice in the choice list. For 3) we need to go back but may need 
backspace quite a bit to get back to before where we started (the only 
place where we can get new choices) -- can that be achieved with a single 
backspace instead?

For example suppose I have abcdefg and abwxyz. I type abc, C-M-/ and 
abcdefg is the sole completion. I may not want it but it would be nice to 
not have to backspace all the way to b to see the other choice. In other 
word if I backspace at all it is understood that I want to go before where 
I started (before where the auto insertion takes place). That would be neat!


@language python
.. @+node:ekr.20111019104425.15861: *3* Scripts to write
.. @+node:ekr.20110917104720.9418: *4* convert-names-to-pep8
This requires real type inference!

We can avoid this if there is only one global def or a name.
.. @+node:ekr.20110918204546.6809: *4* convert-to-class
.. @+node:ekr.20111018104244.15933: *4* Create documentation for commands/plugins
@language rest

Command docs
------------

This will create large docs for individual commands from docstrings.

Base this on print-cmd-docstrings.

Plugins docs


Leo must have a create-plugins-doc script that does the same for
plugins.  A prototype of this script exists somewhere.  Making it an
@command node will make it much more visible. 

Terry wrote plugin_catalog.py.  It is in LeoDocs.leo
.. @+node:ekr.20040123102724: ** Can't or won't do
@language rest
.. @+node:ekr.20130919120947.12506: *3* ** Why Leo won't be a web app
here are two reasons why Leo is unlikely ever to be a web app.

1. There are somewhere around a million lines of Python code in Leo's core
   and plugins. Thus, a *solid* python in javascript system is required.
   This isn't likely to happen.

2. Creating a Leo outline widget is extremely complex. Even starting with a
   working javascript outliner, one has to deal with events (commands)
   coming from Leo scripts rather than from the user.

These seem like the most important obstacles. There may be others, but these
suffice
.. @+node:ekr.20130919120947.12505: *3* Compatibility mode
Leo already works fairly well with vim, emacs and ipython. However, I think
Leo's file format could be friendlier to emacs's org-mode outlines.

I call this project "compatibility mode".

As always, the big question is "what to do about clones?" org-mode uses
sentinels similar to Leo's latest file format, but org-mode knows nothing
of gnx's and clones.

When writing, Leo would simply ignore gnx's. All nodes, clone or not, would
get written in the org-mode format.

As always, there are more choices when reading. One could choose that all
nodes with the same headline and body text would become clones of each
other. Or one could say that clones are never created.

As I write this, I see that org mode could (optionally) put @gnx directives
in the org-mode file, and use same to recreate clones. Of course, this
would pollute the body of the org-mode file, but then one could say that
any other Leo directives could be called form of pollution.

Anyway, the details about clones aren't the main idea. It would be an
important bridge to emacs if (optionally) Leo could write and read standard
org-mode files. Similar remarks probably apply to vim-outline mode.

Org mode won't be part of Leo 4.11, but it might be part of Leo 5.0.
.. @+node:ekr.20120327163022.9740: *3* Improve LeoInspect
.. @+node:ekr.20120623165430.10710: *4* New to do
@nocolor-node

Create global name table.
.. @+node:ekr.20120515193246.10035: *4* To do
@language rest

The leoInspect chapter has a good to-do list:
    
http://webpages.charter.net/edreamleo/leoInspect.html#still-to-do

The assignments_to, assignments_using and the new calls_to getters all
specify a pattern to be matched against the the lhs of assignments (or
against function names in the calls_to getter). At present, the pattern
must match as a plain word match, but it would be more natural to use regex
matches. That’s coming.

Three new getters would give leoInspect the ability to replace refactored code:

    o.token_range: Returns pointers the list of tokens comprising o.
    o.text: Returns o’s source text (a string).
    o.text_range: Returns the starting and ending offsets of the text in the file.

These getters are non-trivial to do, but a reasonable design is in place.
.. @+node:ekr.20120515183732.10136: *4* What I did
@language rest

- Made leoInspect a stand-alone module.
    The code attempts to import leo.core.leoGlobals.
    If that fails, it uses an internal LeoGlobals class.
.. @+node:ekr.20111128103520.10245: *4* Finish leoInspect.token_range
Traverse the tree, setting N.end_lineno and N.end_col_offset.

See the notes below.
.. @+node:ekr.20111129084537.10357: *5* Notes
> All this means that it would likely be too expensive (or just too
> ugly) to compute the data needed for token_range in the base
> AstTraverser class.  Such computations will be performed by traversing
> the module's entire AST the first time "token_range" is called.

There are two parts to the problem.  Happily, neither requires a
separate tree-traversal class.

A token-info prepass
====================

For each node N of a module's tree, we want to inject the following
two new ivars:

- N.end_lineno: the line number of the last character of the token.
- N.end_col_offset: the (byte) offset of the last character of the
token.

After experimenting with a few traversals last night I suddenly
realized tree structure is irrelevant when computing these fields: we
simply want a **sorted** list of (N.lineno,No.col_offset, N) tuples!

The prepass will use ast.walk(root), to generate the list.  After
sorting the list, the prepass will inject inject N.end_lineno and
N.end_col_offset ivars into each node N by stepping through the list.
The ending values of the previous node on the list are the the same as
the beginning values of the next node on the list.

This prepass need only be done once per module.

token_range
===========

To compute token_range for a *particular* N, we want to discover
values M.end_lineno and M.end_col_offset for M, the **last** token in
N's entire tree.

token_range will do the prepass on the modules tree if necessary.
token_range will then call ast.walk(N) to discover all of N's nodes,
sort the list, and return the last element of the list!

In short, token_range is clean and bullet-proof--a happy result.
.. @+node:ekr.20120625183830.11319: *4* Ideas
@nocolor-node

2012/05/20: ideas for LeoInspect

- Want hints/cheats that make computations simpler.
    
- A few hours spent on hints/cheats will pay off because such hints are
  descriptive and useful. They are like unit tests in that regards.
    
- Focus on difficult modules: qtGui.py and leoKeys.py.
    
- The assertions for TypedDict and TypedDictOfLists are ugly. We would like
  a lint-like tool to do away with them.
    
.. @+node:ekr.20040216054459: *3* @h @f @endh and @endf directives
@nocolor

http://sourceforge.net/forum/message.php?msg_id=2424151
By: ksejlod ( Peter Barrel ) 
 I Have a (maybe) great idea!   
2004-02-15 04:29

I've been using LEO for a while and finding surprinsingly powerfull new uses now
and then, (hey, not a week passes that i dont think to myself : "why did'nt
anyone thought of that kind of tool that is LEO. It's so stupid to program such
a tool, yet no one thought of doing such a thing ! ")

I was wondering if there was a leo keyword (beginning with "@") that would do a
feature I thought would be great: something such as :
@h
@endh
and of course, similarily...
@f
@endf

Standing for "Header", "End Header", "Footer" and "End Footer". Let me please explain ...

When creating files with @file (or nosentinels) I use the keyword "@others" in
the starting node body of the file and place in the file, as it's decendants
(children, grand-children & so on) some clones of other stuff somewhere else
outside of this file (usualy, clones of parts of program regrouped as children
of a "components" node up in the leo outline. Typical Example:

-Introduction
-+components
-a
-b
-c
-+@file program.BAS
-b
-c
-a

a, b, and c are clones and the @file node contains @others.

As you see, I proceed that way because in older programming languages or in
lower level languages, the order of components such as procs, declarations, etc
as an importance. It also has the implication that << and >> brackets are
irrelevant in my way of using leo.

Now, my feature that I looked for in the doc but could not find (so i suggest it
here in case no one had any need of this before) is that when used in the BODY
of a node part of an "@file" the @h and @endh would define a chunk of text in
the body, you've guessed it, to be added before _each_ children node and ONLY
children no grandchildren or any deeper. But It could also be used INSIDE the
body of a children to define headers or footers for IT'S OWN direct children.

so, eehh, do you see the relevance of such a feature? Have i explained it
clearly? maybe this would help:'

CONST baba=2 AS INTEGER
CONST bebe=7 AS INTEGER
CONST zaza=5 AS INTEGER
CONST bobo=1 AS INTEGER
... the beginning and end of each of those "parts-of-a-program" is the same for a potential lot of lines... 

To Be Precise : It's just really for adding something at end or beginning of a
direct children of a node part of an @file in the tangling process.

Is this feature already implemented but i have not found it? I'm pretty sure it easy to implement... what do you people think of this?
Thanks 
--
k

p.s. I'm the guy who proposed that in the untangling process, a clone would not
be updated by it's _Last-Instance-Found_ in the @file beeing untangled, but
instead updated by the _Last-Modified-One-Found_ in the @file... :)

(ooouuuuhh that would be slick...)  

By: ksejlod ( Peter Barrel ) 
 RE: I Have a (maybe) great idea!   
2004-02-15 04:35  

 The tree i tried to draw in ascii did not came out the way i did it,
sourceforge "eated" leading spaces sorry a, b and c are children of their "+"
node just above them . -- k
.. @+node:ekr.20130803125244.17077: *3* bug: web site for Leo google group is out of date
@nocolor

From: ne1uno <eltronis@gmail.com>

http://groups.google.com/group/leo-editor/about

still has the old home page webpages.charter.net
though it also has leoeditor.com/ for discussions.

The google docs state that it is not possible to change the web site for a google group.
.. @+node:ekr.20080815174457.5: *3* Consider deleting private shadow files
@nocolor

http://groups.google.com/group/leo-editor/browse_thread/thread/e86796831635311b

I was wondering whether it would be a good idea to have leo
automatically delete the corresponding shadow file when a @shadow node
is deleted? Ditto for deleting the .leo_shadow dir when it is empty.

Answer:

My second thought is that this is too dangerous--shadow files might
turn out to be useful emergency backups.  I would prefer to have Leo
mess with the file system as little as possible.
.. @+node:ekr.20100830120622.5829: *3* Fix python import problems
> > Hmm, I guess that would be more clear, although I think I'd like an option
to include it in the following def to avoid

> > Decoration
> > index
> > Decoration
> > add_user
>
> Sure.  Decorations must always be part of a definition.

Well, personally I'd like to have them included in the definition, but I think
Kent's preference for a separate node is reasonable to. If your function and
hence definition node is called "pluralize", and it's decorated with something
like "@authenticate_user", you may never check the innocent looking pluralize
definition to find out what on earth's triggering the mysterious network
database call. And this isn't a completely specious example, authentication may
have been added to stop pluralize being used in a user existence detection
exploit or something. OTOH in well behaved code like CherryPy apps you don't
want a separate node for every @cherrypy.expose.

Bottom line is I think we're asking for a set of @settings to fine tune python
import behavior:

@python_import_interdef = previous | next | own_node | ai
@python_import_decoration = next | own_node

I'm not sure I believe the AI option is possible / practical, and am not asking
for it, just listing it :-)

I'd also like

@python_import_init_in_class_node = true | false

as often there's more docs on a class in the __init__ than the class docstring.

I think that's really all we're talking about, some @settings to test during import.
.. @+node:ekr.20040329185649: *3* Known Bugs: won't be fixed
.. @+node:ekr.20031218072017.670: *4* Possible webbrowser bug
(In Linux) The home page and online tutorial options in the menu only work
properly if Mozilla window is already open. If not, a Mozilla window opens, but
with empty page and url field.
.. @+node:ekr.20050202073944: *4* Mac bugs
.. @+node:ekr.20050201175325.2: *5* Can't delete script buttons
.. @+node:ekr.20050201175325.1: *5* Icon buttons are not colored, nor do they have square borders, etc.
.. @+node:ekr.20110111100539.12257: *5* Fix end-of-line problem (MacOS)
Apparently, ctrl-e is not passed to Leo at all.

This probably can't be fixed.
.. @+node:ekr.20110111100539.12258: *6* Report
http://mail.google.com/mail/#inbox/12c5646c646a90d2

I expect C-e to go to end-of-line, but C-e works as the next line.
Alt-x and check end-of-line and I get the following result.

I use Mac OS X 10.6.5, newest Leo, and Python/Qt.

Leo 4.8 rc1, build 3715, November 15, 2010
Python 2.6.1, qt version 4.7.0
darwin

I remember I could use C-e, but it doesn't work anymore even after I
reinstall the Leo.

As I explained in this post - http://groups.google.com/group/leo-editor/browse_thread/thread/1ee0b35b4f76c999
After having @bool swap_mac_keys = True, I can use C-e.

C-a move the cursor to the start of line, but C-e seems to move the
cursor the first of the next line, which is the end of last line + 1.
If the line is the final one, C-e moves the cursor to the end of line
as there's no next line.

.. @+node:ekr.20031218072017.673: *4* Tk bugs
The following bugs can not be fixed because they are Tk bugs.

These bugs are becoming moot: Tk will soon be deprecated.
.. @+node:ekr.20081208102356.1: *5* Threading colorizer doesn't handle multiple body editors
http://groups.google.com/group/leo-editor/browse_thread/thread/5be7a099b299327e

> Tk only colorizes one body editor, and if you delete that editor it
> colorizes no editor.

Thanks for this report.  This is a problem, never noticed until now,
with the threading colorizer.  A workaround is to disable the
threading colorizer plugin. 
.. @+node:ekr.20041201071145: *5* Tk Freezes on debean when libtk is compiled with thread support
http://sourceforge.net/forum/message.php?msg_id=2876797
By: skal

By: Grossé Pascal - skal
RE: Leo freezing up  
2004-12-01 06:15

The freezing problem on debian sid (which is also my current OS) is caused by a bug in Tkinter: Tkinter does not work when libtk is compiled with thread support, which is the case on debian sid for tk8.4 
I compiled my own non-threaded libtk with the corresponding python/tkinter, and the freeze magically vanished.  

This is a known bug in debian bugtrack: 

http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=171353 

Skal
.. @+node:EKR.20040523192553: *5* (Crash when pasting large text into headlines)
.. @+node:EKR.20040606104355: *6* Report
@nocolor

From: <eltronic@juno.com>
To: <edreamleo@charter.net>
Sent: Sunday, May 23, 2004 9:36 AM
Subject: fatal bug in Leo headline handling


> found a fatal bug in Leo headline handling.
> not sure if anyone reported before,
> an oversize string can crash python 2.3.3
> 
> 
> the text was about 4500 bytes. nothing but text.
> opened the  leo again, copy a large page of text,
> insert headline, paste, fatal error in python.
> 
> I have by mistake pasted whatever node xml was in 
> the copy buffer into a headline w/o problem.
> but that was just dumb luck. just verified,
> had the node been large enough it crashes.
> 
> Leo 4.1 final, py2.3.3 win98
> PYTHON caused an invalid page fault in
> module TK84.DLL at 0167:1022b74f.
> 
> Leo 4.1 final, py2.2 win98
> paste a 15k node copy into headline. no problem.
> 
> this is the first repeatable hard crash I've stumbled on
> and thought it best to report it privately.
> I can think of no advantage to allowing a headline 
> of this size anyway. think of the tooltip that would create!
> 
> there are latent bugs in the selectall and delete from 
> the edit menu related to headline as well on the todo list.
> reported many times. 
> covert destruction of the selected body text.
> use of virtual events, with out proper focus to headline.
> 
> without myself being able to supply a patch, I'll guess,
> the virtual event paste called can as well point 
> to a function that checks the size before pasting.
> or simply sets the headline directly with 
> g.app.gui.getTextFromClipboard()[:1024]
> 
> 
> e
.. @+node:ekr.20031218072017.674: *5* Caps lock affects keyboard shortcuts on Windows
Using leo under Windows, the keyboard shortcuts seem to use the "Caps Lock" state in determining the shift state when executing a shortcut.   For example, if the caps-lock key is on, then Ctrl-X is interpreted as Shift-Ctrl-X and cuts a node rather than selected text, and Shift-Ctrl-X is interpreted as Ctrl-X and cuts text.
.. @+node:ekr.20031218072017.675: *5* Tree problems
1. The border of the tree control is gray, and it is overwritten with large headlines.  This may be a Tk or Tkinter bug.

2. Adding trailing whitespace to a line in body text does not set the file-dirty mark.  This can never cause a derived file to become "out-of-synch" because the read code does not compare body text.

Apparently there is no way to fix this glitch because of holes in Tk's event mechanism.  Specifically, tree.idle_body_key has no way to tell directly what keystroke caused it to be entered.
.. @+node:ekr.20031218072017.676: *5* Control-T can't be overridden in canvas text.
.. @+node:ekr.20031218072017.677: *5* (Alt-ctrl = Alt)
@nocolor

Read and respond to this message at: 
https://sourceforge.net/forum/message.php?msg_id=1765069
By: dalcolmo

I use the bindings that come with Leo:

[keyboard shortcuts]
pastenode = Shift+Ctrl+V
gonextvisible = Alt+DnArrow
importtofile = Shift+Ctrl+F
writefilenodes = Shift+Ctrl+W
editheadline = Ctrl+H
markchangeditems = Alt+C
replace = Ctrl+=
goprevvisible = Alt+UpArrow
gotonextmarked = Alt+M
readoutlineonly = Shift+Ctrl+R
extractnames = Shift+Ctrl+N
gonext = Alt+Shift+DnArrow
findpanel = Ctrl+F
close = Ctrl+W
demote = Ctrl+}
tangle = Shift+Ctrl+T
extract = Shift+Ctrl+D
openpythonwindow = Alt+P
marksubheads = Alt+S
saveas = Shift+Ctrl+S
cut = Ctrl+X
preferences = Ctrl+Y
equalsizedpanes = Ctrl+E
cantundo = Ctrl+Z
open = Ctrl+O
promote = Ctrl+{
sortsiblings = Alt-A
unmarkall = Alt+U
mark = Ctrl+M
showinvisibles = Alt+V
exit = Ctrl-Q
insertnode = Ctrl+I
findprevious = F4
converttabs = Shift+Ctrl+J
save = Ctrl+S
tanglemarked = Shift+Ctrl+M
moveup = Ctrl+U
copynode = Shift+Ctrl+C
contractparent = Alt+0
selectall = Ctrl+A
setfont = Alt+Shift+T
aborteditheadline = Shift+Esc
goback = Alt+Shift+UpArrow
toggleactivepane = Ctrl+T
findnext = F3
tangleall = Shift+Ctrl+A
endeditheadline = Esc
deletenode = Shift+Ctrl+BkSp
cantredo = Shift+Ctrl+Z
new = Ctrl+N
contractall = Alt+1
moveleft = Ctrl+L
copy = Ctrl+C
paste = Ctrl+V
convertblanks = Shift+Ctrl+B
expandall = Alt+9
markchangedroots = Alt+R
cutnode = Shift+Ctrl+X
indent = Ctrl+]
gotonextchanged = Alt+D
expandnextlevel = Alt+=
setcolors = Alt+Shift+S
matchbrackets = Ctrl+K
movedown = Ctrl+D
clonenode = Ctrl+`
untangle = Shift+Ctrl+U
expandtolevel7 = Alt+7
expandtolevel6 = Alt+6
expandtolevel5 = Alt+5
expandtolevel4 = Alt+4
expandtolevel3 = Alt+3
expandtolevel2 = Alt+2
moveright = Ctrl+R
unindent = Ctrl+[
replacethenfind = Ctrl+-
extractsection = Shift+Ctrl+E
expandtolevel8 = Alt+8


However, I use a utility called AllChars (Free as in beer :-(  ) to be able
to type all kinds of chars on my US keyboard, and "Handything" to place the
windows on the screen (Win2000). Perhaps this makes a difference, although disabling
them did not seem to make it go away. Still, on pressing alt+ctrl+uparrow I
end up at the next upper node etc...

- Josef

.. @+node:ekr.20031218072017.718: *5* (tab bug)
.. @+node:ekr.20040117092727: *6* This is definitely a Tk bug
By: dthein ( Dave Hein ) 
 RE: BUG: Non-leading tabs not working properl   
2004-01-17 14:40  

 This seems to be a TK bug. I've reproduced the problem directly in Tk.

It's been around for a long time :-(

More details on this page, along with a patch for an earlier version.

http://www.qs.co.nz/Tcl/TkTabs.html

The Tk folks fixed a bug I reported with Ctrl-V behavior, but it took about a year for them to get to it. I don't have high expectations with this problem either, but I'll probably put together a patch for some of the recent version of Tk and submit the patches and bug report.  
.. @+node:ekr.20040118090055: *6* Patch and bug report
https://sourceforge.net/forum/message.php?msg_id=2380238
By: dthein

I've submitted a patch and bug report to the Tk project.

The patch, #879073, for those that want to fix this problem on their systems,
is at:

http://sourceforge.net/tracker/?func=detail&aid=879073&group_id=12997&atid=31299
7

And the bug report, #879077, is at:

http://sourceforge.net/tracker/?func=detail&aid=879077&group_id=12997&atid=11299
7

The patch is for 8.4.2.  If you have a different version, you can probably figure
out the changes needed by looking at the patch file.  If not, let me know your
version and I may be able to produce a patch for it.

Note: If you use tabs for anything other than leading whitespace, you will find
this patch really helpful.  I make lots of little tables when I'm documenting
or note-taking ... this fix really helped my sanity when making those tables
inside Leo.

Dave Hein
.. @+node:ekr.20031218072017.719: *6* Report
@nocolor

Read and respond to this message at: 
https://sourceforge.net/forum/message.php?msg_id=1906790
By: dspeed
Open Discussion

-- Tabs are not expanded correctly in .c files, when language in preferences is set to c, and when the tabs occur in the middle of a line. The tabs are expanded as spaces until the next tab location is reached, then the tabs are expanded correctly. 
.. @+node:ekr.20040105070023.5: *6* Report 2
Leo 4.1 rc3, build 1.62 , December 19, 2003
Python 2.3.0, Tk 8.4.2
Linux 2.4.22-21mdkenterprise

1. Any tab typed before the first tab stop behaves correctly (the cursor is moved to the tab stop). Good.

2. Any tab typed after a non-tab character (even a space) _and_ after the first tab stop position doesn't behave like a tab and doesn't move the cursor to the next tab stop. Bad.

3. Any tab typed after a tab character will behave properly no matter what position on the line. Okay.

To reproduce this, set your global tab prefernence to 4. Show invisibles. And then create a node containing:

[BEGIN BODY TEXT]
@language plain
@tabwidth 8
[END BODY TEXT]

Create a child node to that one, containing:

[BEGIN BODY TEXT]
@root-code somefilename
\t\tThis works
bbb\tAnd This works
So\tdoes this

But, this \tdoes not.
Here is the two-tab \t\t behavior.
[END BODY TEXT]

I hope this is a Leo bug and not a Tk bug. 

Dave Hein 
.. @+node:ekr.20031218072017.720: *6* Minimal test
This is a test line.
.. @+node:ekr.20031218072017.721: *6* Test File for Non Expanding Tabs
This is a test line.
put the text insertion point in the space between 'a' and 'test' above. Enter 3 tabs in a row and watch it not work.

If your expansion works correctly, then maybe something with leoconfig?  But wait, Im using the leoconfig from the beta download.

The contents of my Log Windows when opening this file:

Leo Log Window...
Pyton 2.2.2, Tk 8.3.2
reading d:\test.leo


.. @+node:ekr.20031218072017.672: *5* Control-V doesn't work on Linux
This has been and continues to be a known issue with Tk. Has been logged as a
bug; no response from the Tk folks.

Here is a link to the Tk bug report: 

http://sourceforge.net/tracker/?func=detail&aid=605277&group_id=12997&atid=112997 

Note the work-around/patch in the followup post at the bottom of that page. Commenting out some statements in text.tcl removes the problem. 
.. @+node:ekr.20040220110030: *5* Change cursor when caps lock is down
@nocolor

http://sourceforge.net/forum/message.php?msg_id=2431552
By: nobody

From: Rich

 I just got nipped twice by the following effect: the Caps-Lock key is ON, but
because the LED is on the Caps-Lock key, it is hidden behind my hand. I hit
Ctrl-x, expecting to cut my selection, but the entire node is cut.

   I know there's a problem with tk and the shift key status, so I'm wondering
if it would be possible to change the shape of the cursor when the Caps-Lock
is ON (preferrably a big red flashing blot 8-), or otherwise show that Caps-Lock
is active ( "CAPS" on a status line, for instance).

  Another way: I don't know if this goes against an "anti-modalism rule," but
only allowing Ctrl-Shift-x|c|v in the outline pane would also be acceptable
to me.
.. @+node:ekr.20040115165036: *4* bug in xml doc parts (hard to fix?)
@language html
@ignore
@color
.. @+node:ekr.20040115165036.1: *5* Demo XML comment bug
@ 
This document demonstrates what appears to be a bug in Leo 4.1 rc3, build 1.62 of December 19, 2003.

It has manifested when Leo is executed under Python 2.3.3, Tk 8.4.3 under Windows 2000.

In brief, derived XML files are not well-formed with respect to comments under some conditions.  Comments can wind up nested, which looks okay to humans but not to XML parsers.
@c
.. @+node:ekr.20040115165036.3: *5* @file xmlcommentbug.xml
@first
@language HTML
<HiMom>
@
This will produce, in the derived file, an XML comment with another XML comment
embedded. Or, if you prefer, it will produce an unclosed XML comment followed by
a well-formed one, followed by a string of text containing a comment-close
marker.

This text is sitting in the inner comment, according to the first view.
@c


@
This comment is well-formed, seemingly because its content does not begin on the
same line as the at-sign.
@c
</HiMom>
.. @+node:ekr.20040115165036.4: *5* xmlcommentbug.xml
<?xml version='1.0'?>
<!--@+leo-ver=4-->
<!--@+node:@file xmlcommentbug.xml-->
<!--@@first-->
<!--@@language HTML-->
<HiMom>
<!--@+at -->
<!--
<!--@nonl-->
This will produce, in the derived file, an XML comment with another XML 
comment embedded.  Or, if you prefer, it will produce an unclosed XML comment 
followed by a well-formed one, followed by a string of text containing a 
comment-close marker.

This text is sitting in the inner comment, according to the first view.
-->
<!--@-at-->
<!--@@c-->


<!--@+at-->
<!--
This comment is well-formed, seemingly because its content does not begin on 
the same line as the at-sign.
-->
<!--@-at-->
<!--@@c-->
</HiMom>
<!--@nonl-->
<!--@-node:@file xmlcommentbug.xml-->
<!--@-leo-->
.. @+node:ekr.20111011062533.15693: *3* Make headline widgets scrollable
# It doesn't seem easy.
.. @+node:ekr.20110605121601.18422: *4* editLabelHelper (leoQtTree)
def editLabelHelper (self,item,selectAll=False,selection=None):

    '''Called by nativeTree.editLabel to do
    gui-specific stuff.'''

    trace = False and not g.unitTesting
    w = self.treeWidget
    w.setCurrentItem(item)
        # Must do this first.
        # This generates a call to onTreeSelect.
    w.editItem(item)
        # Generates focus-in event that tree doesn't report.
    e = w.itemWidget(item,0) # A QLineEdit.
    if e:
        s = e.text() ; len_s = len(s)
        if s == 'newHeadline': selectAll=True
        if selection:
            i,j,ins = selection
            start,n = i,abs(i-j)
                # Not right for backward searches.
        elif selectAll: start,n,ins = 0,len_s,len_s
        else:           start,n,ins = len_s,0,len_s
        e.setObjectName('headline')
        e.setSelection(start,n)
        # e.setCursorPosition(ins) # Does not work.
        e.setFocus()
        wrapper = self.connectEditorWidget(e,item) # Hook up the widget.
    if trace: g.trace(e,wrapper)
    return e,wrapper # 2011/02/11
.. @+node:ekr.20110619173515.14896: *3* Wrong modality level on autocompleter
Just noticed the autocompleter pop-up is modal globally, not just for
the Leo windows.  Probably should only block the Leo windows.
.. @+node:ekr.20131019061259.16697: *3* Fix broken links on Leo's web site
found 27 broken links.

http://leoeditor.com/images/edit_note.html
http://leoeditor.com/images/toolbar.html
http://leoeditor.com/images/delete.html
http://leoeditor.com/images/editcopy.html
http://leoeditor.com/images/duedate.html
http://leoeditor.com/slides/external-files/index.html
http://leoeditor.com/slides/leo-basics-step-by-step/_sources/slide-010.html
http://leoeditor.com/images/newlist.html
http://leoeditor.com/images/new_item.html
http://leoeditor.com/images/owners.html
http://leoeditor.com/images/complete.html
http://leoeditor.com/images/openlist.html
http://leoeditor.com/images/editcut.html
http://leoeditor.com/images/print.html
http://leoeditor.com/slides/installation/index.html
http://leoeditor.com/images/refresh.html
http://leoeditor.com/slides/using-leos-minibuffer/index.html
http://leoeditor.com/images/editpaste.html
http://leoeditor.com/slides/installation/_static/underscore.html
http://leoeditor.com/images/find.html
http://leoeditor.com/front.html
http://leoeditor.com/slides/scripting-leo/index.html
http://leoeditor.com/images/printprev.html
http://leoeditor.com/slides/leo-basics-step-by-step/index.html
http://leoeditor.com/slides/clones-and-views/index.html
http://leoeditor.com/images/mail_item.html
http://leoeditor.com/images/page_setup.html
.. @+node:ekr.20120516140545.9987: ** Ideas
.. @+node:ekr.20120515193246.10087: *3* * DOM
.. @+node:ekr.20071001052501: *4* Versioning for nodes
@nocolor

One feature I have not seen in SCS system is something which might be called
"history compression": I might be interested in having both version 5 and 6
in my source tree, when the current version is 7, but I am not really interested
in the 2000 steps which transformed 5 into 6 (just suggested this feature to
the bazaar people). This happens actually quite often to me, since I use the
SCS as a back-up system, saving many (uninteresting) intermediate steps while
implementing a new feature.
.. @+node:ekr.20080802070659.11: *4* Make node attributes visible, and supported by Leo's core
.. @+node:ekr.20111019104425.15896: *4* Enhansed node attributes: ctime, atime, mtime (Kent)
.. @+node:ekr.20111027103125.16546: *4* Fossil
@nocolor-node

http://groups.google.com/group/leo-editor/browse_thread/thread/19bfe6daf2b324/c50a750606d64f77

Fossil (SCCS) and Leo.

> I think that the interaction of Fossil + Leo could
> solve the idea of having external files in a single "Leo document" that
> would be really a fossil sqlite repository with all the external files in
> it, but syncronizable with the outside world. This kind of instantiated
> image of files in a moment of time in Fossil + Leo, would be like the
> instantiated image of objects in a moment of time of Smalltalk.
.. @+node:ekr.20120515193246.10088: *3* * Tools
.. @+node:ekr.20110921094450.6959: *4* Code tools
Analysis, checking, refactoring and other code-level tools are a natural for
Leo. When the new-lint project is mature, it could be folded into Leo.
.. @+node:ekr.20110921094450.6960: *4* Documentation tools
Perhaps Leo's documentation could be built primarily from docstrings. In any
event, documentation tools are always needed.
.. @+node:ekr.20111019104425.15894: *4* Wizards (Kent)
Leverage the template capability to offer form-based content creation:
- create a plugin
- generate a test node
- generate a wizard :-]
.. @+node:ekr.20100521090440.5890: *3* Code Cleanups
# These are hardly worth doing.
.. @+node:ekr.20130914103322.11285: *4* * Reorganize leoAtFile.py
@language rest

Each read/write operation should create a *separate* reader or writer object.
This prevents any possibility of pollution of ivars.
.. @+node:ekr.20100223123910.5930: *4* recentFilesController
@
The present operation of recent files is surprising.

Recent files should be a global list, managed by a single controller.
.. @+node:ekr.20100219083854.5615: *4* Improve caching
.. @+node:ekr.20100209160132.5770: *5* cache notes
Top-level folder are direct subfolders of .leo/db.
Top-level folders represent file *locations* not file contents.
Exception: the top-level "globals" folder represents minor data.

Only two files are ever needed in a top-level folder:

contents_<key>: the contents of the file.
data_<key>: a dict representing the "minor data" of the file:
    <globals> element stuff, expansion bits, etc.

We write contents_<key> only once.
By definition, its contents never changes, since the contents generates the key.
We can write data_<key> as many times as we like.

To do:
- Simplify or even eliminate the path-manipulation code in PickleShareDB.
- Use g.makeAllNonExistentDirectories to make top-level directories.
- Clear cache should clear all top-level directories.
.. @+node:ekr.20100209114432.5751: *6* Cache expansion bits
# Simplify the structure of the cache: put more into the "minor" files.
.. @+node:ekr.20100211095442.6201: *5* cache notes 2
1. Memory does leak, and that's not ok with me.  And I want just two
files per top-level directory.

2. Strange things can happen with caching, as just happened to me when
I restored qtui_generate.py mistakenly deleted from leo/test.  There
is an @auto node for this file in qtGui.py, and I got improper 'can
not open' messages for this file.

3. It is troubling that the present caching scheme does not use the
full path to a file, only the basename.  This means that two identical
files in two different places will use the same cache entries.  I've
been wondering for the last several days about whether this could
cause problems.  I don't know for sure, but I am uncomfortable.

4. I want the clear-cache and clear-all-caches commands to do what
they say: get rid of everything.  Among other things, this is good for
debugging and recovering from cache problems.

.. @+node:ekr.20100223075705.5635: *5* Don't write expansion bits
.. @+node:ekr.20100210163813.5748: *5* Caching buglets?
This is a recent bug, but imo it has uncovered some other caching buglets. These
buglets are not big enough to delay Leo 4.7, but the new caching scheme would
ensure they never bite.

1. The code that computes what I have been calling the top-level directory is dubious::

    dbdirname = join(g.app.homeLeoDir,'db',
            '%s_%s' % (bname,hashlib.md5(fn).hexdigest()))

The problem is that bname is only the base name of the cached file, not a name
(or key) that depends on the full path. Thus, two copies of the same file in the
same place will be cached in the same directory. Is this ominous?

2. It's not clear what caching to do with the save-to command.
.. @+node:ekr.20100225102636.5627: *5* Use the string returned by cacher
# It should be possible to avoid duplicate reads.
.. @+node:ekr.20111012061216.15699: *4* Use @g.command for all Leo commands?
.. @+node:ekr.20080628095358.1: *4* Make each Leo command a class
http://groups.google.com/group/leo-editor/browse_thread/thread/5688ed9aaa39be2e#

@nocolor

The main difficulty I see in the migration is creating the tables in the getPublicCommands methods in the various classes in leoEditCommands.py.  At present, these tables associate command names (strings) with corresponding methods.  The form of getPublicCommands is always:

def getPublicCommands (self):
  return {
    'command-name1': self.methodName1,
    'command-name2': self.methodName2,
    ...
  }

Thinking out loud, let's see whether the migration can be done easily.  We would change the entry:

    'command-name1': self.methodNameN,

to:

    'command-name1': self.classNameN(self),

That is, the table creates an instance of the class by calling the class's ctor, with self (the container object) as the ctor's only argument.  To make this work, all we need to do is give the class a __call__ method whose signature matches the signature of methodNameN, that is, the signature used to call methods previously.

Well, isn't this nice.  We can transition gradually, as needed.  No need *ever* to do a mass migration.  It should be easy to verify this scheme with one or two examples.  Please report your experiences if you decide to play around with this.

Edward

P.S.  I think it would be good style to append "Class" to the name of each command class. This makes it clear that self.myCommandClass(self) is a ctor.
.. @+node:ekr.20101119030344.5838: *5* script to turn all commands into @g.command nodes
'''Add @g.command(command_name) before all commands.'''

@others

import os ; os.system('cls')

d = c.commandsDict
f_dict = find_all_defs(c)

result1, result2 = [],[]
for f_name in sorted(f_dict): # These are function names, not command name.
    c_name = c.k.inverseCommandsDict.get(f_name) # Get the emacs command name.
    if c_name:
        f = d.get(c_name) # f is the function name that defines a command.
        if f:
            d_name = f.__name__
            s = repr(f)
            tag = '<bound method '
            if s.startswith(tag): s = s[len(tag):]
            i = s.find(' of ')
            if i > -1: s = s[:i]
            aList = [p.h for i,p in f_dict.get(d_name,[])]
            if len(aList) == 1:
                result1.append((d_name,s,aList),)
            else:
                result2.append((d_name,s,aList),)

print('----- duplicate commands -----\n')
for d_name,s,aList in result2:
    print('%s: %s\n%s %s\n' % (d_name,s,len(aList),aList))

print('----- unambiguous commands -----\n')
for d_name,s,aList in result1:
    print('%40s %s' % (d_name,aList[0]))

if 0:
    for name in sorted(d):
        f = d.get(name)
        f_name = f.__name__
        # name is the minibuffer command name, f_name is the function name.
        i,p = find(c,command,f_name)
        adjust(c,f_name,i,p)
.. @+node:ekr.20101119030344.5841: *6* find_all_defs
def find_all_defs (c):

    '''Return a dict containing all function defs.

    Keys are function names, values are lists of (i,p) pairs.'''

    # To do: consider only files that actually generate commands?
    d = {}
    suppress = ('__init__',)
    for p in c.all_unique_positions():
        done,i,s = False,0,p.b
        while not done and i < len(s):
            progress = i
            i = i1 = s.find('def',i)
            if i == -1:
                done = True ; break
            i += 3 # Assures progress.
            if not g.match_word(s,i-3,'def'): continue
            j = g.skip_ws(s,i)
            if j == i: continue
            i = j
            j = g.skip_id(s,i,chars='_')
            if j == i: continue
            name = s[i:j]
            if name not in suppress:
                aList = d.get(name,[])
                aList.append((i1,p.copy()),)
                d[name] = aList
            # g.trace('%30s %s' % (name,p.h))
            i = j
            assert progress < i
    return d
.. @+node:ekr.20101119030344.5839: *6* find
def find (c,command,f_name):

    g.trace('%30s %s' % (command,f_name))

    for p in c.all_unique_nodes():
        s = p.b
        i = s.find('def %s' % f_name)
.. @+node:ekr.20101119030344.5840: *6* adjust
def adjust(f,i,p):
    pass
.. @+node:ekr.20080923200153.1: *4* Support scan-directives hook again?
# This affects the add_directives plugin.
# Also, the color_markup plugin doesn't work with the threading colorizer.
.. @+node:ekr.20110614123640.6587: *4* Add headline/color functions to Leo's core
@nocolor-node

http://groups.google.com/group/leo-editor/browse_thread/thread/7e279fe3dedf42be/f00fde4df5b39ded

What uA should be used to specify node colors?

if the foreground / background color API uses uAs,
would/should the uAs use the reserved "leo_&lt;something&gt;"
namespace?

-------------------

Terry Brown

Sounds like something I may have brought up, long ago.

I was thinking that setting the fore/background color of nodes in the
tree should be a "gui core" function, and that the info should be
stored in uA, and so wanted to know what key should be used in uA for
that.  I think the docs say top level keys starting with "leo_" are
reserved, and probably wanted a ruling on

v.u['leo_fg'] = 'red'

vs

v.u['leo_tree_style']['fg'] = 'red'

etc.

I think the question may be more complicated than just what to call the
key, so you can probably retire the todo item.
.. @+node:ekr.20111101050427.16716: *4* Make g.openWithFileName "reentrant"
@nocolor-node

That is, make sure it works when called from within itself.
.. @+node:ekr.20120229094652.15178: *3* Commands
.. @+node:ekr.20111010122531.15569: *4* print-bindings/commands/settings create nodes??
@language rest

http://groups.google.com/group/leo-editor/browse_thread/thread/d302b2715b3ace96

A reminder, the opposite of "light" is "heavy", not "dark" :-)

Leo's print-settings, print-commands and print-bindings commands
create too much text.

Suppose they created outline nodes instead, replacing existing nodes
if they exist.  Something like this:

- Reference (Anywhere you like)
 - @print-settings
    etc.
 - @print-bindings
   etc
 - @print commands
   etc

Doh!  This uses Leo's power.  The subnodes can be as voluminous as
desired, and there can be organizer nodes in each case.  The actual
tree could be specified as in @menus.

Etc., etc.  This could moot the need for separate apropos commands.
Conversely, apropos commands could create their own trees, or
subtrees.

This could be the tip of an iceberg.

The more I think about the light/heavy distinction, the more I think
it is getting close to what makes Leo special.  For example, clones
(and nodes, for that matter) drastically lighten the apparent
complexity of programs or data.
.. @+node:ekr.20120515193246.10083: *4* Find & spell
.. @+node:ekr.20111018104244.15928: *5* Improve Find panel
@nocolor-node

- All open files.
- Show all results as in quicksearch.
.. @+node:ekr.20111014134653.15672: *5* Search across multiple Leo files
http://groups.google.com/group/leo-editor/browse_thread/thread/cf5ab54f29a6c128
.. @+node:ekr.20051110155735.1: *5* Improve Spell tab & spell checker
@nocolor

- Per-pane key bindings. (arrows, etc.)
- Try default fonts for spell buttons.
- Select the first entry.

@color
.. @+node:ekr.20090907080624.6081: *6* Spell checker should check headlines
.. @+node:ekr.20110520051220.18203: *5* Cross-tab search
@language rest

This would be a substitute for cross-file clones.
.. @+node:ekr.20111027143736.16558: *5* Work-flow improvements
@nocolor-node

Considering leo.leo
http://groups.google.com/group/leo-editor/browse_thread/thread/e3ddbe650fc9525b/290e97c593ee950a

> > I think there's a way to search across Leo files: quicksearch multiple
> > files ... ?

> http://groups.google.com/group/leo-editor/browse_thread/thread/cf5ab5...

Leo has to have this :-)  It's on my list.  It would be a great way to
find @button nodes.

Furthermore, global searches for attributes in docstrings have
immediate uses.

On the urgent to-do list: drive all aspects of the Nav pane using
keystrokes.

I just reviewed @bookmarks--it's perfect for leo.leo.  The following
would replace all.bat:

- @bookmarks
  - leoPy.leo (url in body)
  - leoPlugins.leo
  - leoSettings.leo
  - myLeoSettings.leo
  - leoDocs.leo
  - leoDist.leo
  - scripts.leo

This way could be said to be much better than all.bat: nothing gets
loaded until needed.  Therefore, even more files could be added.

Imo, URL's in bookmark trees should support {{expression}} notations.

For example, I want the following to work in the body text of a node
in an @bookmarks tree::

file://{{g.os_path_finalize_join(g.app.loadDir,'..','doc','LeoDocs.leo').replace('\\','/')}}

Not bad, eh?  Or maybe the URL logic should do the replace('\\','/')
automatically...

Got to go.  We are nearing a tipping point in Leo's workflow... 
.. @+node:ekr.20041022083005.2: *5* add a Stop button for find/change
.. @+node:ekr.20041219162724: *5* Add dialog to insert recent directories
http://sourceforge.net/forum/message.php?msg_id=2903742
By: nobody

In the multifile plugin there is an option to insert a directory string.  I
use it alot for the @path directive.  What happens is that when executed a FileDialog
opens up and the user selects the directory he wants to use as a directory string.
When chosen the directory string is inserted into the text editor.

The good of this:
1. It makes using path simpler, you dont have to type out the directory path
yourself, just use the tkFileDialog to select it and have Leo insert the string.
For long directories this saves a lot of typing.

simple, short and quite helpful.  Thoughts? :)

-----------

Time to create a directory class??

.. @+node:ekr.20120515193246.10084: *4* Import/export
.. @+node:ekr.20110613110911.16421: *5* Read/write files in json format
.. @+node:ekr.20111009230326.7037: *6* Leo-to-json script for IPython?
.. @+node:ekr.20110527084258.18378: *7* New file format
@nocolor-node

** remove window state, expansion status etc.
   stuff from .leo file, and move that over to c.db

- <attr> solves pickle problem.

* Treat gnx's as strings: don't parse them.
  http://mail.google.com/mail/#inbox/12f3d4950fbabeea
  
* Don't save expansion bits in uA if not saving expansion bits. It's illogical
  to save bits in uA's if they aren't save in in the <v> elements.
  
    @bool put_expansion_bits_in_leo_files = False

- Use uuid's?

- Remove spaces from user names.

.. @+node:ekr.20110609042343.16546: *8* Notes
.. @+node:ekr.20110609042343.16548: *9* File format, v3 draft 5
@language rest
@pagewidth 65

http://groups.google.com/group/leo-editor/browse_thread/thread/2ddb57c62e67825c

Leo's file format: version 3, draft 5

This draft is intended to reflect minimal changes from Leo's
present file format, but with improvements mentioned at the
Ashland sprint and developed afterward.

This draft covers only Leo's xml format, but it may be adapted
for use as a json file format.

This draft contains significant invention by EKR. See the next
section. Don't panic: it can be changed :-)

Summary of changes from draft 4
===============================

- Elements will be renamed as follows::

    old         new
    ====        ====
    <vnodes>    <directed-acyclic-graph>
    <tnodes>    <data-list>
    <v>         <node>
    <t>         <data>

- Nesting of <node> elements represents the structure of the DAG,
  just as nesting of <v> elements does at present.
  
- Thus, there will be no <edge> elements.

- Headlines will move from <v> elements to <data> elements.
  This "normalizes" the data: headlines will appear only once.
  
- <attr> elements will represent uA's.  A full discussion below.

  Ideally, I would like to support only string and json formats
  for <attr> elements.  This is open to discussion. 

- Only <node> elements will contain <attr> elements.

- <node> elements for @file nodes will contain
  <at-file-attributes> elements, representing Leo's "hidden
  machinery" attributes.  <at-file-attributes> will contain
  <attr> elements. 

First lines
===========

Leo file will start with the following::

    <?xml version="1.0" encoding="utf-8"?>
    <?xml-stylesheet my_stylesheet?>
    <!-- Created by Leo (http://webpages.charter.net/edreamleo/front.html) -->
    <leo_file file_format="3"
        xmlns:leo="http://www.leo-editor.org/2011/leo"/>
        

No session data
===============

There will be no <globals>, <preferences> or
<find_panel_settings> elements. All such "session data" will be
restored from the cache, or from defaults if caching is disabled.

**Important**: there is no representation of expansion state or
the currently selected node anywhere in the .leo file.
Eliminating these data is contingent on having Leo work well with
caching disabled.

Note: marks are more than session data. They must appear within
<node> elements.


Summary of format
=================

.leo files will have the following form, with similar indentation::

    <?xml version="1.0" encoding="utf-8"?>
    <?xml-stylesheet my_stylesheet?>
    <!-- Created by Leo (http://webpages.charter.net/edreamleo/front.html) -->
    <leo_file file_format="3" xmlns:leo="http://www.leo-editor.org/2011/leo"/>
    <directed-acyclic-graph>
        <node id="gnx">
            <!-- contained node elements, if any.
        </node>
        <node id="gnx">
            <!-- contained v elements, if any.
        </node>
        ...
    </directed-acyclic-graph>
    <data-list>
        <data id="gnx">
            <!-- marked attribute appears only if the tnode/vnode is marked -->
            <head>headline text</head>
            <attr key="marked">1</attr>
            <!-- uA's... -->
            <!-- format="string" is the default -->
            <attr key="a">a string</attr>
            <attr key="b" format="json">a json string</attr>
            <attr key="c" format="pickle">a pickled string</attr>
            <attr key="d" format="binhex">a binhexed string</attr>
            ...
            <body>body text</body>
        </data>
        ...
    </data-list>
    </leo_file>

<attr> elements
===============

<attr> elements will one of the following forms::

    <attr key="a">a unicode string</attr>
    <attr key="b" format="json">a json string</attr>
    <attr key="c" format="pickle">a json string</attr>
    <attr key="d" format="binhex">a binhexed string</attr>
    
The value will be a string by default.

If possible, I would like to support only the string and json
formats. This would make the data as transparent as possible.
Please mentally amend the following discussion...

uA's that start with "binhex_" will use the binhex format. This
prefix must be retained in the type field, so the read code can
restore them.

If the value is not a string, and there is no "binhex_" prefix,
the write code will use format="json" if json.dumps succeeds, and
will use format="pickle" otherwise.

No <attr> element will be written if both json.dumps and
pickle.dumps fail. Attribute failures will create a warning for
the plugin developer.
    
Descendant attributes in @file trees
====================================

Descendants of @file nodes do not appear in .leo files. Thus,
important data must be stored in the so-called hidden machinery:
attributes of the @file node.

The <at-file-attributes> element may optionally be contained in
the <node> element for @file nodes::

    <at-file-attributes>
        <attr>key="ua-name"
            format="(empty)/json/pickle/binhex"
            gnx="gnx">value
        </attr>
        ...
    </at-file-attributes>
.. @+node:ekr.20110421132230.6107: *9* File format, v3 draft 4
@language rest
@pagewidth 65

Leo's file format: version 3, draft 4

http://groups.google.com/group/leo-editor/browse_thread/thread/a2b7e5321d62b64/a4cc51d404af94aa

Here is the latest version, with the graphml stuff removed.

This draft is intended to reflect our recent discussions, with no
new invention from me. All comments and corrections welcome.

This draft covers only Leo's xml format, but it may be adapted
for use as a json file format.

Recent changes
==============

- Removed graphml stuff, including leo: prefixes.

- Used "key" in <attr> elements (and "type" in <edge> elements.)

First lines
===========

Leo file will start with the following::

    <?xml version="1.0" encoding="utf-8"?>
    <?xml-stylesheet my_stylesheet?>
    <!-- Created by Leo (http://webpages.charter.net/edreamleo/front.html) -->
    <leo_file file_format="3"
        xmlns:leo="http://www.leo-editor.org/2011/leo"/>
        

No session data
===============

There will be no <globals>, <preferences> or
<find_panel_settings> elements. All such "session data" will be
restored from the cache, or from defaults if caching is disabled.

**Important**: there is no representation of expansion state or
the currently selected node anywhere in the .leo file.
Eliminating these data is contingent on having Leo work well with
caching disabled.

Note: marks are more than session data. They must appear
somewhere within <node> elements.


Summary of format
=================

.leo files will have the following form, with similar indentation::

    <?xml version="1.0" encoding="utf-8"?>
    <?xml-stylesheet my_stylesheet?>
    <!-- Created by Leo (http://webpages.charter.net/edreamleo/front.html) -->
    <leo_file file_format="3" xmlns:leo="http://www.leo-editor.org/2011/leo"/>
    <graph>
    <nodes>
        <!-- marked attribute appears only if the vnode is marked -->
        <node id="gnx"> 
            <head>headline text</head>
            <attr key="marked">1</attr>
            <!-- uA's... -->
            <!-- format="string" is the default -->
            <attr key="a">a string</attr>
            <attr key="b" format="json">a json string</attr>
            <attr key="c" format="pickle">a pickled string</attr>
            <attr key="d" format="binhex">a binhexed string</attr>
            ...
            <body>body text</body>
        </node>
        ...
        <!-- @file nodes contain a <data> package -->
        <node id="gnx">
            <head>@file x.py</head>
            ...
            <at-file-attributes>
                <attr>key="ua-name"
                    format="(empty)/json/pickle/binhex"
                    gnx="gnx">value
                </attr>
                ...
            </at-file-attributes>
        </node>
        ...
    </nodes>
    <edges>
        <edge type="child" from="gnx" to="gnx"</edge>
        ...
    </edges>
    </graph>
    </leo_file>

<attr> elements
===============

<attr> elements will one of the following forms::

    <attr key="a">a unicode string</attr>
    <attr key="b" format="json">a json string</attr>
    <attr key="c" format="pickle">a json string</attr>
    <attr key="d" format="binhex">a binhexed string</attr>
    
That is, the value will be a string by default.

uA's that start with "binhex_" will use the binhex format. This
prefix must be retained in the type field, so the read code can
restore them.

If the value is not a string, and there is no "binhex_" prefix,
the write code will use format="json" if json.dumps succeeds, and
will use format="pickle" otherwise.

No <attr> element will be written if both json.dumps and
pickle.dumps fail. Attribute failures will create a warning for
the plugin developer.

<edge> elements
===============

<edge> elements will have the form::

    <edge type="child" from="gnx" to="gnx"/>
    
Leo will use type="child" to represent Leo's official edges.
Plugins are free to define any type except "child". Examples::

    <edge type="undirected" from="gnx" to="gnx"/>
    <edge type="bidirectional" from="gnx" to="gnx"/>
    <edge type="backlink" from="gnx" to="gnx"/>
    <edge type="myPlugin" from="gnx" to="gnx"/>
    
Descendant attributes in @file trees
====================================

Descendants of @file nodes do not appear in .leo files. Thus,
important data must be stored in the so-called hidden machinery:
attributes of the @file node.

The <at-file-attributes> element may be contained in the
<node> element for @file nodes::

    <at-file-attributes>
        <attr>key="ua-name"
            format="(empty)/json/pickle/binhex"
            gnx="gnx">value
        </attr>
        ...
    </at-file-attributes>
    
In other words, we use the graphml <attr> element, extended with the
gnx attribute, to represent all the uA's in the descendants of @file nodes.
.. @+node:ekr.20110419083918.6104: *9* File format, v3 graphml
@language rest
@pagewidth 65

This draft is intended to reflect our recent discussions, with no
new invention from me. All comments and corrections welcome.

The draft is also intended to be compatible with graphml.

This draft covers only Leo's xml format, but it may be adapted
for use as a json file format.

I am willing to change "type" to "key" in <edge> elements if that
would be preferable.

Recent changes
==============

- Added <graphml> element defining the default namespace.

- Defined the leo namespace for leo-only elements.
    - Renamed <leo_file> to <leo:outline>
    - Renamed <descendant-attributes> to <leo:at-file-attributes>

- Used <leo:at-file-attributes> for marks, removing the special case.

- Enclosed <leo:descendant-attributes> in a (graphml) <data> element.

- Changed the format of the "marked" attribute to be a string-valued attribute.

First lines
===========

Leo file will start with the following::

    <?xml version="1.0" encoding="utf-8"?>
    <?xml-stylesheet my_stylesheet?>
    <!-- Created by Leo (http://webpages.charter.net/edreamleo/front.html) -->
    <leo:file file_format="3"
        xmlns:leo="http://www.leo-editor.org/2011/leo"/>
    <graphml xmlns="http://graphml.graphdrawing.org/xmlns"/>
        

No session data
===============

There will be no <globals>, <preferences> or
<find_panel_settings> elements. All such "session data" will be
restored from the cache, or from defaults if caching is disabled.

**Important**: there is no representation of expansion state or
the currently selected node anywhere in the .leo file.
Eliminating these data is contingent on having Leo work well with
caching disabled.

Note: marks are more than session data. They must appear
somewhere within <node> elements.


Summary of format
=================

.leo files will have the following form, with similar indentation::

    <?xml version="1.0" encoding="utf-8"?>
    <?xml-stylesheet my_stylesheet?>
    <!-- Created by Leo (http://webpages.charter.net/edreamleo/front.html) -->
    <leo:outline file_format="3" xmlns:leo="http://www.leo-editor.org/2011/leo"/>
    <graphml xmlns="http://graphml.graphdrawing.org/xmlns"/>
    <graph>
    <nodes>
        <!-- marked attribute appears only if the vnode is marked -->
        <node id="gnx"> 
            <head>headline text</head>
            <attr key="marked">1</attr>
            <!-- uA's... -->
            <!-- format="string" is the default -->
            <attr key="a">a string</attr>
            <attr key="b" format="json">a json string</attr>
            <attr key="c" format="pickle">a pickled string</attr>
            <attr key="d" format="binhex">a binhexed string</attr>
            ...
            <body>body text</body>
        </node>
        ...
        <!-- @file nodes contain a <data> package -->
        <node id="gnx">
            <head>@file x.py</head>
            ...
            <data>
                <leo:at-file-attributes>
                    <attr>key="ua-name"
                        format="(empty)/json/pickle/binhex"
                        gnx="gnx">value
                    </attr>
                    ...
                </leo:at-file-attributes>
            </data>
        </node>
        ...
    </nodes>
    <edges>
        <edge type="child" from="gnx" to="gnx"</edge>
        ...
    </edges>
    </graph>
    </graphml>
    </leo:outline>

<attr> elements
===============

<attr> elements will one of the following forms::

    <attr key="a">a unicode string</attr>
    <attr key="b" format="json">a json string</attr>
    <attr key="c" format="pickle">a json string</attr>
    <attr key="d" format="binhex">a binhexed string</attr>
    
That is, the value will be a string by default.

uA's that start with "binhex_" will use the binhex format. This
prefix must be retained in the type field, so the read code can
restore them.

If the value is not a string, and there is no "binhex_" prefix,
the write code will use format="json" if json.dumps succeeds, and
will use format="pickle" otherwise.

No <attr> element will be written if both json.dumps and
pickle.dumps fail. Attribute failures will create a warning for
the plugin developer.

<edge> elements
===============

<edge> elements will have the form::

    <edge type="child" from="gnx" to="gnx"/>
    
Leo will use type="child" to represent Leo's official edges.
Plugins are free to define any type except "child". Examples::

    <edge type="undirected" from="gnx" to="gnx"/>
    <edge type="bidirectional" from="gnx" to="gnx"/>
    <edge type="backlink" from="gnx" to="gnx"/>
    <edge type="myPlugin" from="gnx" to="gnx"/>
    
Descendant attributes in @file trees
====================================

Descendants of @file nodes do not appear in .leo files. Thus,
important data must be stored in the so-called hidden machinery:
attributes of the @file node.

The <leo:at-file-attributes> element may be contained in the
<node> element for @file nodes. For compatibility with graphml,
it will enclosed in a data element::
    
    <data>
        <leo:at-file-attributes>
            <attr>key="ua-name"
                format="(empty)/json/pickle/binhex"
                gnx="gnx">value
            </attr>
            ...
        </leo:at-file-attributes>
    </data>
    
In other words, we use the graphml <attr> element, extended with the
gnx attribute, to represent all the uA's in the descendants of @file nodes.
.. @+node:ekr.20090218115025.3: *9* Why are attributes pickled by default?
@nocolor-node

http://groups.google.com/group/leo-editor/browse_thread/thread/326a221f4c698f7a

> On Wed, Feb 18, 2009 at 12:12 PM, Kent Tenney <ktenney@gmail.com> wrote:
>>
>> Currently, Leo pickles the value of unknown attributes unless
>> the name starts with 'str_'
>>
>> Running the following code in node 'UA'
>>
>> p = c.currentPosition()
>> p.v.u = {'hello':'world', 'str_hello':'world'}
>>
>> results in the following in the .leo file:
>>
>> <v t="ktenney.20090218114928.367" str_hello="world"
>> hello="5505776f726c6471002e"><vh>UA</vh></v>
>>
>> I think this is surprising, Python-centric and contrary to the
>> spirit of Leo as a flexible data management platform.
>
> I suppose your point is that you can't create an arbitrarily named attribute
> with a string value. Does that create a real problem?

It requires a translation layer, either to (un)munge the name or
(un)pickle. Real problem?

Let's say each time I think 'I can use UAs to store that' I change
my mind when I realize my values will be in a pickle. (I really don't
want to name all my attributes str_xxx)

> As far as being Python-centric, can you suggest any other way of converting
> arbitrary data to a text string?

How is it done in any other XML file?
I've not used XML for arbitrary data, but it probably can be done.

> Why would that way be better than pickle?

My suspicion is that UAs would be used more for
storing text and numbers (as seems common for XML files)
than Python data objects.

Does Leo use UAs to store pickles?

I'm sure pickling capability is great, but I'm not convinced
it should be the _default._

No big deal.
.. @+node:ekr.20110415173840.6098: *8* Code related to uA's
.. @+node:ekr.20040701065235.2: *9* fc.putDescendentAttributes
def putDescendentAttributes (self,p):

    nodeIndices = g.app.nodeIndices

    # Create lists of all tnodes whose vnodes are marked or expanded.
    marks = [] ; expanded = []
    for p in p.subtree():
        v = p.v
        if p.isMarked() and p.v not in marks:
            marks.append(v)
        if p.hasChildren() and p.isExpanded() and v not in expanded:
            expanded.append(v)

    result = []
    for theList,tag in ((marks,"marks"),(expanded,"expanded")):
        if theList:
            sList = []
            for v in theList:
                sList.append("%s," % nodeIndices.toString(v.fileIndex))
            s = ''.join(sList)
            # g.trace(tag,[str(p.h) for p in theList])
            result.append('\n%s="%s"' % (tag,s))

    return ''.join(result)
.. @+node:ekr.20080805071954.2: *9* fc.putDescendentVnodeUas
def putDescendentVnodeUas (self,p):

    '''Return the a uA field for descendent vnode attributes,
    suitable for reconstituting uA's for anonymous vnodes.'''

    trace = False
    if trace: g.trace(p.h)

    # Create aList of tuples (p,v) having a valid unknownAttributes dict.
    # Create dictionary: keys are vnodes, values are corresonding archived positions.
    pDict = {} ; aList = []
    for p2 in p.self_and_subtree():
        if hasattr(p2.v,"unknownAttributes"):
            aList.append((p2.copy(),p2.v),)
            pDict[p2.v] = p2.archivedPosition(root_p=p)

    # Create aList of pairs (v,d) where d contains only pickleable entries.
    if aList: aList = self.createUaList(aList)
    if not aList: return ''

    # Create d, an enclosing dict to hold all the inner dicts.
    d = {}
    for v,d2 in aList:
        aList2 = [str(z) for z in pDict.get(v)]
        # g.trace(aList2)
        key = '.'.join(aList2)
        d[key]=d2

    if trace: g.trace(p.h,g.dictToString(d))

    # Pickle and hexlify d
    return d and self.pickle(
        torv=p.v,val=d,tag='descendentVnodeUnknownAttributes') or ''
.. @+node:EKR.20040526202501: *9* fc.putUnknownAttributes
def putUnknownAttributes (self,torv):

    """Put pickleable values for all keys in torv.unknownAttributes dictionary."""

    attrDict = torv.unknownAttributes
    if type(attrDict) != type({}):
        g.warning("ignoring non-dictionary unknownAttributes for",torv)
        return ''
    else:
        val = ''.join([self.putUaHelper(torv,key,val) for key,val in attrDict.items()])
        # g.trace(torv,attrDict)
        return val
.. @+node:ekr.20090130114732.6: *9* v.u Property
def __get_u(self):
    v = self
    if not hasattr(v,'unknownAttributes'):
        v.unknownAttributes = {}
    return v.unknownAttributes

def __set_u(self,val):
    v = self
    if val is None:
        if hasattr(v,'unknownAttributes'):
            delattr(v,'unknownAttributes')
    elif type(val) == type({}):
        v.unknownAttributes = val
    else:
        raise ValueError

u = property(
    __get_u, __set_u,
    doc = "vnode unknownAttribute property")
.. @+node:ekr.20101004092958.5914: *5* Write treepad scanner
@ treepad.py is from the treepad website
.. @+node:ekr.20101004092958.5939: *6* treepad.py
@first #! /usr/local/bin/python

# treepad.py

@language python
@tabwidth -4
@others
if __name__ == '__main__':
    Main().Run()

.. @+node:ekr.20101004092958.5940: *7* treepad declarations
import sys, os, re, string

# constants
VERSION = "<Treepad version 2.7>"

# regexes
END_RE = re.compile(r'^<end node> ([^ ]+)$')
.. @+node:ekr.20101004092958.5941: *7* class Node
class Node:
    @others
.. @+node:ekr.20101004092958.5942: *8* __init__ (Node/treepad)
def __init__(self):
    self.title    = ""
    self.level    = 0
    self.article  = []
    self.children = []
    self.parent   = None
    self.end      = ""
.. @+node:ekr.20101004092958.5943: *8* __str__
def __str__(self):
    return "%s/%d" % (self.title, self.level)
.. @+node:ekr.20101004092958.5944: *8* addchild
def addchild(self, node):
    assert self.level == node.level-1 and node.parent is None
    node.parent = self
    self.children.append( node )
.. @+node:ekr.20101004092958.5945: *8* findparent
def findparent(self, node):
    if self.level == (node.level-1): return self
    return self.parent.findparent(node)
.. @+node:ekr.20101004092958.5946: *8* writenode
def writenode(self, fp):
    fp.write("dt=Text\n")
    fp.write("<node>\n")
    fp.write("%s\n" % self.title)
    fp.write("%s\n" % self.level)
    for line in self.article:
        fp.write("%s\n" % line)
    fp.write("<end node> %s\n" % self.end)
.. @+node:ekr.20101004092958.5947: *8* writetree
def writetree(self, fp):
    self.writenode(fp)
    for node in self.children:
        node.writetree(fp)

.. @+node:ekr.20101004092958.5948: *7* class NodeReader
class NodeReader:
    @others
.. @+node:ekr.20101004092958.5949: *8* __init__ (NodeReader)
def __init__(self, fname, fp):
    self.fname    = fname
    self.fp       = fp
.. @+node:ekr.20101004092958.5950: *8* expect
def expect(self, text, line=None):
    if line is None:
        line = self.fp.readline().strip()
    assert line == text, "expected " + line + " == " + text
.. @+node:ekr.20101004092958.5951: *8* readstart
def readstart(self):
    self.expect(VERSION)
.. @+node:ekr.20101004092958.5952: *8* readnode
def readnode(self):
    line = self.fp.readline()
    if line is None:
        return None
    line = line.strip()
    if len(line) < 1:
        return None
    self.expect("dt=Text", line)
    self.expect("<node>")
    node = Node()
    node.title = self.fp.readline().strip()
    node.level = int(self.fp.readline().strip())
    while 1:
        line = self.fp.readline()
        m = re.match(END_RE, line)
        if m:
            node.end = m.group(1).strip()
            break
        node.article.append( line.strip() )
    return node

.. @+node:ekr.20101004092958.5953: *7* class TreeReader
class TreeReader:
    @others
.. @+node:ekr.20101004092958.5954: *8* __init__(TreeReader)
def __init__(self, fname, fp=None):
    if fp is None: fp = open(fname, 'r')
    self.nodereader = NodeReader(fname, fp)
    self.root = None
    self.prev = None
.. @+node:ekr.20101004092958.5955: *8* add
def add(self, node):
    if self.prev is None:
        assert node.level == 0
        self.root = node
    else:
        assert node.level > 0
        parent = self.prev.findparent(node)
        parent.addchild( node )
    self.prev = node
.. @+node:ekr.20101004092958.5956: *8* read
def read(self):
    self.nodereader.readstart()
    prev = None
    while 1:
        node = self.nodereader.readnode()
        if node is None: break
        self.add(node)

.. @+node:ekr.20101004092958.5957: *7* class TreeWriter
class TreeWriter:
    @others
.. @+node:ekr.20101004092958.5958: *8* __init__ (TreeWriter)
def __init__(self, fname, fp=None):
    if fp is None: fp = open(fname, 'w')
    self.fname = fname
    self.fp    = fp
.. @+node:ekr.20101004092958.5959: *8* write
def write(self, root):
    self.fp.write("%s\n" % VERSION)
    root.writetree(self.fp)

.. @+node:ekr.20101004092958.5960: *7* class Main
class Main:
    @others
.. @+node:ekr.20101004092958.5961: *8* __init__ (Main)
def __init__(self):
    self.infile  = sys.argv[1]
    self.outfile = sys.argv[2]
    self.reader  = TreeReader(self.infile)
    self.writer  = TreeWriter(self.outfile)
.. @+node:ekr.20101004092958.5962: *8* Run

def Run(self):
    self.reader.read()
    self.writer.write(self.reader.root)

.. @+node:ekr.20031218072017.790: *5* Import dialog improvements
@nocolor

Other options I though would be really handy:

1. Use an existing node as a source also

2. Use an node from another Leo file.. I am not sure what the syntax for that
would be exactly

3. From a URL.. this would be really cool. People could post outlines not only
as existing Leo xml files, but as text files or even dynamic scripts. The code
to handle these would presumably need to deal with http:// intelligently. But
that's easy in Python. Rebol is great at that too.

4. Other XML file with valid filepaths in them.
That's probably a much bigger project like Leo 3.10  

Jason
.. @+node:ekr.20060227124411: *5* Import/export from wiki's
@nocolor
http://sourceforge.net/forum/message.php?msg_id=3583737
By: Offray

I was previously thinking in the relation between Leo and Wikis, and I think
that may be a thing that would help to make Leo more visible in Wiki space could
be if Leo can export/import to/from a Wiki (something limilar to th @file or
@url directives). Let me explain a little better the scenary where this idea
come.

We have a local wiki for colombian Free Software Community related issues, and
I have used Leo for writing the migration scripts from Mediawiki to MoinMoin
(wich I think is more flexible and extensible that the popular wiki behind
wikipedia). I was probing also the idea of a Wiki like environment for solving
colaborative problems, so I was posting the scripts I made on Leo in a Wiki
page, and republishing them in the moment they changed. This keeps me pasting
all the time the script and in some moments I was thinking what about if someone
make a change in the Wiki page. Would be nice then to have the same capability
to detect and sincronize that change as Leo make with the hard disk files.

But this doesnt end here. Another Wiki-Leo interaction is to use outlines as
a way to organice Wiki content. For example "= Title =" in a Wiki would be a
Outline Node in Leo and "== Subtitle ==" Would become a outline subnode all
arranged in the proper hierarchy.

Somekind of Wisiwyg display would be nice, but this must be a plugin or something
like that, so Leo could become a "Layered" front end to some kind of data.

About and article on Wikipedia. That would be nice, but I'm a little tired of
fighting with some wikipedians ignorance on certain matters combined with power
(a pretty bad combination). I think that a Wiki page is nice because its live
comes from the community knowledge, but I'm not interested in that fighting,
so I have made a Leo wiki page in our local Wiki:

http://www.el-directorio.org:8080/Leo

and when I have enough knowledge about Leo (and time) I hope to start making
contribs in the spanish documentation (for the moment I'm only workind in the
evangelism here).
.. @+node:ekr.20031218072017.748: *5* Import/Export to yaml
Need a good yaml parser first: I don't want to write another parser by hand.
.. @+node:ekr.20110525112110.18398: *4* Other
.. @+node:ekr.20041130123243: *5* Clear Undo command
@killcolor

http://sourceforge.net/forum/message.php?msg_id=2859273
e

theres a config option to clear undo on save.
can that be a menu choice as well? 
clear undo now.
enable clear undo on save.
moot as it will be with the new config options
and any undo changes on the table.
maybe there is a single point to involke clear 
undo that could be run from a button?

with py2.3 after allot of small edits on an open leo after a few hours gc can
hit unexpectedly and last several minutes
and return at any time lasting several more minutes.
I think its gc related because the memory use and disk grinding demanding I
free up memory or kill python.

I have no idea if undo is the cause,
 just guessing.
using cvs of last week. I just updated, 
will let you know if it happens again.
(new error reporting jump to error is great)

usually I don't edit in the same process that long.
I have run scripts from leo that run 6, 12 
or 24 hours no problem. 
maybe I can turn on some internals reporting and
get some feedback on whats going on from python if it happens again. 
or run the gc script before and after.

 win98 128meg w/maxmem memory defrager that works well.
but I go from 50% free to 10% when this starts happening.
I haven't noticed this problem yet in py2.4, and it is peppier,
but don't use py2.4 enough. it doesn't happen every day.
I reboot at least once a day for various reasons.
so it isn't that either. 
you do need to reboot and or exit python once it starts.
this was never an issue with py2.2 and Leo 4.1 or less with only 64 megs.
I don't really have any other long running python processes to compare to Leo. 
can't say what it is.
Aha, progress. 
this started sometime early in 4.2 or late 4.1
but I can still be persuaded something in my 
local system is to blame, some install or dll update. or script, psyco or plugin
related.

nonwithstanding, I should be taking better advantage Moore's law in my CPU and
memory.
I only notice this when I'm running the same leo over a few hours of constant
editing and running scrips.
and when I exit python and restart leo everything returns to normal.
more a supporting anomaly report 
than a bug report or feature request.
.. @+node:ekr.20050127110221: *5* Printing & flash
@killcolor
https://sourceforge.net/forum/message.php?msg_id=2962825
By: jasonic

-- pdf -- 
yes I know what you mean, PDF has it uses.  If nicely embedded into Leo via
'reportwriter'  and some export scripts {and clear useinterfance} would stillbe
a good thing.


As I start to think about how to print Leo, I become more aware of the differneces
between Leo structures and linear [print] layouts.

Different kinds of outlines obviously will need different kinds of printing.
I don't yet have enough experience or overview.

--xslt--
Seems a natural way to go for printing Leo, but yet another langauge and syntax
to wrassle with. Last time I looked I went from being horrified to very impressed
to be being exhausted.

--htmlize--
thanks I'll check into that

"print to web"  should definitely be on Leo's missing PRINT MENU.

--swf [flash]--
This printing topic pushes me harder to get FLC  [my FlashLeoClient project]
into the Leosphere.

Flash has*limited*  CSS handling, but enough to do some nice and useful typographic
formatting in a pretty clean object-oriented manner.

FLC parses .leo files into a Flash object. Flash Textformat instances are created
using CSS and can be applied then to rendering any parts of  the deserialized
Leo object.. The beauty is it can be very fast and ynamic so I can imagine a
real-time WYSIWYG laytou tool for printing Leo to web and at the same making
it suitable at the same time for print-to-paper.

Since FLC is in the very first instance a READ-ONLY client tool for Leo, it
makes it a natural Leo printing service.

To complete full service, it woudl be good if Leo could create SWF files directly
itself, just like using PDF reportwriter.
There are a couple of libraries to help this 
- Ming [with PHP, Perl, Python and Ruby wrappers]
http://ming.sourceforge.net/

- makeswf.r [interesting REBOL/Flash dialect by David Oldes]
http://sweb.cz/oliva.david/swf/

These could also be both configured as web-services.
So Leo print-to-web would include by default rendering a flash swf file versoin
of itself either using locally installed libraries or by passing a view of itself
to a chosen client or server-based tool.

But even without those extra 'services' and libraries a single flash file in
the form of FLC could become an effective Leo printing kit. Using a standalone
desktop  version [not embedded in the browser, out of the sandbox] much more
is possible - remote control, peer-peer editing, file writing etc.

-- flashpaper2--
btw, Lately I've been using Flashpaper2 a lot to print all kinds of stuff, Often
from web pages to my local adhoc home filebase. It's a very fast lighweight
alternative to PDF, saves paper, has excellent zooming and nice search features
built-in.
Flashpaper renders a very litteral snapshot, but as I am discovering that turns
out to be extremely useful.
For example you visit a page and click on some links. Flashpaper saves teh pages
exactly as it looks, viisted links disntinguished.  In the era of info-overload,
even that crude mnemonic is valuable.

Alas, Flashpaper2 is not free nor open in the way Leo is. But worth to play
with it if only for for the experience.
30 day trial downlaod from
http://www.macromedia.com/software/flashpaper/

And of course the flash _players_ is free, so can send people flashpaper documents
just like PDF.
Brilliant when you have a big Excel spreadsheet or CAD document which would
normally get all messy printing across pages, confusing people.
Instead adjust and print to a generous 'piece' of flashpaper - letting your
coleagues pan and zoom to their comfort.

I've not quite figured out the place where  Leo meets Flashpaper, because Leo
needs to preserve its full pane contents. Flashpaper works fine with long web
pages, automatically reading the full window contents and cutting into a paginated
sequence, ready for paper printing.
Leo's does not have aprint menu, so it's off the sytem's print-devices map,
which Flash paper appearing just  like any phtycial printer.

I imagine is possible to fix that in Leo, but I do not where to begin and woudl
not be surprised to learn its a major heachche to write adn debug for multiple
operating systems.

An immediate alternative are screencapture tools like vnc2swf or MDM Capture.

[vnc2swf uses Ming-0.2a]
http://www.unixuser.org/~euske/vnc2swf/

http://www.multidmedia.com/software/capture/index.php

But much is hidden or lost from view. 
Still very vauable for creating dynamic narrative tutorials [aka screencasting]

AS you know I am very excited about what flash can do for Leo, and vice versa.
But I am concerned that there is not yet a 100% Leo means which supports people's
standard print needs and habits.

-- PRINT MENU-- 
Leo deserves good friendly printing features which anyone can use. At the moment
we have a confusing patchwork of choices. Printing Leo seems to be both harder
and easier than  first meets the eye.

Having a little library of export scripts - well named, documented and intended
to aid printing woudl go a long way. Thesse scripts anyone coiuld be called
by onayone given a Leo Outline, accessing a navabr button. PRINT MENU or list.
Or they can just insert the appropriate script  into an outline giving finer
grained print control on the fly.
.. @+node:ekr.20031218072017.807: *5* Put up file dialog on empty @url, etc.
@nocolor

Open Discussion
https://sourceforge.net/forum/message.php?msg_id=2003457
By: dsalomoni

Proposal: modify the code for @url so that if you type for example just "@url"
(no file specified) in a headline, a window pops up allowing you to browse the
local file system and select the file (similar to what browsers do when you
want to open a file).

This would be more convenient than manually writing @url
file://a/long/path/to/the/file. @read-only nodes already allow this, it would
perhaps be nice if all these types of plugins (@folder might be another one
for example) and directives (@file etc) had the same behavior (and this should
probably be specified in some guidelines for writing new plugins -see e.g. the
jedit plugin guidelines).

Davide
.. @+node:ekr.20041016134312.2: *5* Standard Weave command
Use noweb and TeX, or maybe Pyx.
.. @+node:ekr.20110525112110.18397: *5* Minor Emacs support
.. @+node:ekr.20060123091352: *6* Incremental search in switch-to-buffer
.. @+node:ekr.20060116090428: *6* Expand 'point' so it indicates node as well as text location
.. @+node:ekr.20051021074728: *6* Space completion
.. @+node:ekr.20111017132257.15883: *5* Possible to use IPython completion?
@language rest

http://groups.google.com/group/leo-editor/browse_thread/thread/014fe61ff9480b2b

I don't know if this is relevant or not, but the IPython autocompletion
capability is awesome.

If I'm investigating code I tend to do the following.

list the modules in a package:
In [1]: from fs import <tab>

this lists the modules, in a package so I pick one
In [1]: from fs import osfs
<the osfs entry is tab-completable>

now I can check the usage of fs.osfs
In [2]: osfs? <enter>

or the source:
In [2]: osfs?? <enter>

or the contents of the module
In [2]: osfs. <tab>

I can instantiate a class:
In [3]: myfs = osfs.OSFS('/')

and examine the ivars and methods:
In [4]: myfs. <tab>

It is such an efficient way to learn and remember the details of code.

I know a bunch of work was done on Leo/IPython integration, don't
know the current status, my wish of synchronized IPython and Leo
may well be one of the many granted wishes I have forgotten about.

I certainly think IPython autocompletion is the gold standard. 
.. @+node:ekr.20041022083226: *3* Directives
.. @+node:ekr.20031218072017.805: *4* Allow other section delims besides << and >>
Maybe the section operator could be customizable, 
I personally prefer the wiki way [[name of section]]. 

@setlink-tag [[ ]] 
.. @+node:ekr.20031218072017.745: *4* @@first <n>
@nocolor

Hate to break into the grand design discussions, but here's a hopefully small thing. If you need to place a good sized copyright statement at the top of your files, LEO doesn't handle this case very cleanly. As I'm sure you're aware, you wind up with a matching number of @@first lines for each leading line in your source. 

As an example: 
# 1 
# 2 
# 3 
# 4 
# 5 
@verbatim
@verbatim
@verbatim
#@+leo 
@verbatim
@verbatim
@verbatim
#@+node:0::@file /tmp/firstcheck.py 
@verbatim
@verbatim
@verbatim
#@+body 
@verbatim
@verbatim
@verbatim
#@@first 
@verbatim
@verbatim
@verbatim
#@@first 
@verbatim
@verbatim
@verbatim
#@@first 
@verbatim
@verbatim
@verbatim
#@@first 
@verbatim
@verbatim
@verbatim
#@@first 
@verbatim
@verbatim
@verbatim
#@+doc 
# 
# How many firsts do I get? 

@verbatim
@verbatim
@verbatim
#@-doc 
@verbatim
@verbatim
@verbatim
#@@c 
Start code. 
@verbatim
@verbatim
@verbatim
#@-body 
@verbatim
@verbatim
@verbatim
#@-node:0::@file /tmp/firstcheck.py 
@verbatim
@verbatim
@verbatim
#@-leo 

My fellow co-workers who don't use LEO, aren't exactly loving me here. 

Might we introduce an: 

@@first <num> 

Type tag instead? So one '@@first 5' could represent all 5 of the above @@first lines? It makes for a smaller, cleaner LEO footprint and will tick off non-LEO users much less. 

Thanks. 

- ordinarius 
.. @+node:ekr.20031218072017.795: *4* Metatags
@nocolor

By: nobody ( Nobody/Anonymous ) 
 RE: 3.11 todo list & schedule   
2003-02-11 03:25  

Here are some features I'd like to see: 

3. Metatags. @sectionname or @savedate are expanded to the appropriate text when saved.

-marshall-  

There are quite a few of these now.  It would be good to generalize:
- Register @node type.
.. @+node:ekr.20041130104552: *4* (Support bird-track programs/comments?)
@killcolor

By: Guenther Enthaler - genthaler
RE: Haskell support  
2004-11-18 22:55

There's a literate programming mode in Haskell (and in a number of other
functional programming languages such as Clean & Curry), where the program is in
a comment, usually where the line starts with ">" (bird track style, I think
it's called), and the comments/documentation are freeform. It would be difficult
but cool if Leo could support it, if only because the sentinels in the derived
files wouldn't make whole file look so busy.

Günther 
.. @+node:ekr.20031218072017.797: *4* Allow @file http & @file ftp
@nocolor

I'd like to see leo's @file can be extended to cover more protocols, like REBOL's "read" does. 

in short, it would be very sweet if the following work: 

@file http://www.somedomain.org/python/foo.py 

@file pass@ftp.sd.org/python/foo.py" target="_blank" target="_new">ftp://user:pass@ftp.sd.org/python/foo.py> 

while we are at it, what about xmlrpc/soap? 

should there be new directive, like @source ?

@color
.. @+node:ekr.20031218072017.810: *5* Remote access Scott Powell
I will wait. Here's clarification, when you're ready for it:

All of my projects are stored on remote computers, and accessed via FTP. 
What I want is basically the ability to open up these projects directly 
through leo, instead of transferring the files manually between my computer 
and the computers that hold my projects, preferably through FTP.

My solution: A new menu item called 'FTP' or 'Remote'. Click on this, and an 
FTP dialog opens up, with an empty list of FTP sites, and the ability to add 
more. You select a site, and it brings up a list of files. You select a 
file, and it is added to your project. When you hit 'save', it automatically 
does an FTP send.

Python makes this a lot easier with the builtin module 'ftplib'. I'm sure 
there are similar things for C++. I hope you take this idea into 
consideration.

Scott Powell
CEO, Dev Designs
.. @+node:ekr.20110525112110.18401: *3* Docs
.. @+node:ekr.20111018104244.15924: *4* Revise Leo's wiki
.. @+node:ekr.20090131200406.15: *3* File
.. @+node:ekr.20080311135649.2: *4* Allow different .leo formats
@nocolor

On Tue, Mar 11, 2008 at 7:03 AM, Kent Tenney <kten...@gmail.com> wrote:

> On 3/11/08, derwisch <johannes.hues...@med.uni-heidelberg.de> wrote:

> >  On 11 Mrz., 08:03, "Ville M. Vainio" <vivai...@gmail.com> wrote:
> >  > It could also be argued that

> >  > - Referring to previous cloned vnodes explicitly in XML does not
> >  > necessarily obscure DAG - it follows the "do not repeat yourself"
> rule
> >  > - It will speed up reading
> >  > - Wouldn't it be better for preserving the integrity of the XML file?

> > I would lean towards this line of argumentation. A couple of days I
> >  had my Leo extension destroy the Leo ODM file (which was still valid
> >  according to Leo, but unreadable wrt the extension and broken uAs). I
> >  resorted to editing the Leo file with Emacs, and was quite surprised
> >  to see that the headStrings were attributes of vnodes.

> I'll chime in with my pet peeve re: .leo file structure::

> I think that putting the headstrings on vnodes and body strings on tnodes
> obscures the informational content of the .leo file, and makes the .leo
> file
> format less attractive as a generalized solution to the problem of how to
> manage head/body pairs which live in a hierarchal structure.

> Thanks,
> Kent

> >  I think that
> >  editing the file might have been a bit easier if there had been no
> >  such redundancy. But this is more a feeling rather than a qualified
> >  opinion.

Thanks for all these comments.  I'll respond to them all here.

Clearly, we should be using a standard xml parser to read .leo files.

My present thoughts:

- I personally like human-readable headlines in <v> elements.

- I am open to putting headlines in <t> elements, as an indication that
tnodes do indeed contain headlines and body text.

- I am willing to consider only writing shared subtrees once.

Oh! (An Aha)  All these are preferences.  We can allow any combination of
these provided that headlines appear somewhere.

So that's clean.  This will happen in Leo 4.5. 
.. @+node:ekr.20061002093442: *4* Add opml support to new,open, save commands
.. @+node:ekr.20071003104917: *4* Make http://edreamleo.org/namespaces/leo-python-editor/1.1 Leo's official namespace
xmlns:leo="http://edreamleo.org/namespaces/leo-python-editor/1.1"
.. @+node:ekr.20080626081829.2: *4* Allow headline comments for @nosent files
@nocolor

http://groups.google.com/group/leo-editor/browse_thread/thread/eb718b4c6d478ac0

I'm just getting started learning how to use Leo. Now, I'd like to use
it for some of my projects, but there's no chance that I can convert
everyone at work to using it, so putting sentinel-filled files in our
repository is out of the question. At the same time, my code looks
awfully bare without sentinels because the documentation ends up in
the section names, not the comments!

So, I was wondering if there's a convenient way to pull the section
names into a comment at the start of each section?

===============

Interesting question.  Am I correct in assuming you are using @nosent trees
to generate your files?  If so, it would be easy to add support for the
following options:

@bool write_section_comments_in_at_nosent_trees
@bool write_node_name_comments_in_at_nosent_trees

The first would write a sentinel consisting of only the section name;
the second would write a sentinel consisting only of the node's headline
(for nodes whose headline is not a section name).

These seem like they would be useful additions.  One can even imagine
corresponding Leo directives so that the comments could be turned on or off
within an @nosent tree.

What do you think?

=====================

> Interesting question.  Am I correct in assuming you are using @nosent trees
> to generate your files?  If so, it would be easy to add support for the
> following options:

> @bool write_section_comments_in_at_nosent_trees
> @bool write_node_name_comments_in_at_nosent_trees

> The first would write a sentinel consisting of only the section name;
> the second would write a sentinel consisting only of the node's headline
> (for nodes whose headline is not a section name).

> These seem like they would be useful additions.  One can even imagine
> corresponding Leo directives so that the comments could be turned on or off
> within an @nosent tree.

That sounds like an excellent solution. Particularly the last bit --
if you could turn section-comments on and off as required, it would
become very convenient to use Leo to produce source that is intended
to also be read by non Leo users. 
.. @+node:ekr.20080919085541.3: *4* Use sqlite data base as an alternative representation for .leo files
http://groups.google.com/group/leo-editor/browse_thread/thread/dff0c165e2211691
.. @+node:ekr.20080922115725.1: *4* Finish @shadow
# Allow block comments in private shadow files.
# Compute delims using the private shadow file, not the file extension!
# Can @shadow mark externally changed nodes?
.. @+node:ekr.20081004102201.2: *5* Log file for @shadow
http://groups.google.com/group/leo-editor/browse_thread/thread/5e7bd3af2d1fbf51

How about a shadow.log file which Leo told what it thought of the relationship
between the node, file and shadow? It might provide useful clues.
.. @+node:ekr.20081001062423.1: *5* Can @shadow mark externally changed nodes?
http://groups.google.com/group/leo-editor/browse_thread/thread/c46eabe8a9fe6e8
.. @+node:ekr.20090402072059.13: *5* Create a general mechanism for aux (shadow, _db) files
http://groups.google.com/group/leo-editor/browse_thread/thread/4ec30df3f1db8db3

On Sat, Mar 28, 2009 at 3:24 AM, VR <viktor.ransmayr@gmail.com> wrote:


    When I tried to de-install Leo-4.6b1 I succeeded, but the program
    reported that 5 directories
    were not removed.

    Three of the directories where

    1) C:\Python26\Lib\site-packages\Leo-4-6-b1\leo\config
    2) C:\Python26\Lib\site-packages\Leo-4-6-b1\leo\doc
    3) C:\Python26\Lib\site-packages\Leo-4-6-b1\leo\plugins

    [containing]


    a) .leoSettings.leo_db
    b) .leoDocs.leo_db
    c) .leo_shadow
    d) .leoPluginsRef.leo_db


Thanks for this report. I think it is important, and needs a good solution.

I dislike all these files being sprayed around the file system. I'd like to see
these files placed somewhere the ~/.leo directory. Is there a reason why this
would be a bad idea?

Similarly, we might also prefer to have shadow files place in, say,
~/.leo/shadow_files.

In both cases, I think we want to create files that indicate their location.
Either that, or mirror their location in (subdirectories) ~/.leo. In other
words, this is a general problem, and it would be good to have a robust, general
solution.
.. @+node:ekr.20100826110728.5839: *5* Relocating .leo_shadow directories
2008

http://groups.google.com/group/leo-editor/browse_thread/thread/b738e3f8d164f9fc

May 10, 2010

Kent

I think there could be quite a bit of interest in moving
the shadow files to their own tree, avoiding what might
be considered 'pollution' of a tree of files in @shadow nodes.

Edward has said that this would add a lot of complexity to Leo.

It seems that a VCS back end for Leo might simplify the
task of arbitrary shadow file location, as well as adding
versioning capability.


Those of us old enough to remember the Groucho Marx show will know what I am ...

bogomil
 to me

In order to relocate .leo_shadow directories in home dir, I have made
the following changes leoShadow.py:
1. Introduce new setting 'shadow_in_home_dir':
   x.ctor:
     ...
     self.shadow_prefix = c.config.getString('shadow_prefix') or ''

=>  self.shadow_in_home_dir = c.config.getBool('shadow_in_home_dir')
or False
    ...

2. Make the following line:
   x.shadowDirName and shadowPathName:
      ...
      fileDir = g.os_path_dirname(filename)

=>   if self.shadow_in_home_dir:
        fileDir = "//".join([baseDir, fileDir.replace(':','%')])

In this way I keep .leo_shadow dirs in a tree and it is ok if the user
reorgs the original tree.

=====================
Edward K. Ream
 to bogomil

Thanks for these suggestions.  I'll try them soon.

A few minor comments about the code.

>  self.shadow_in_home_dir = c.config.getBool('shadow_in_home_dir') or False

This works (because c.config.getBool returns None if the setting does
not exist). Thus, the "or False" part merely replaces None by False.
I prefer the following:

self.shadow_in_home_dir = c.config.getBool('shadow_in_home_dir',default=False)

>   if self.shadow_in_home_dir:
>         fileDir = "//".join([baseDir, fileDir.replace(':','%')])

This looks like a Windows-only solution because of ':'.  It might fail
in strange ways on other platforms.
.. @+node:ekr.20120515193246.10085: *3* Gui
.. @+node:ekr.20120516140545.9988: *4* Features
.. @+node:ekr.20110621085435.6532: *5* Request: have equal-sized-panes resize vr pane
@nocolor-node

http://groups.google.com/group/leo-editor/browse_thread/thread/583bc0a31a6c7979

I noticed that when the renderpane is active it is not affected by the
Window>Equal Sized Panes command. Only the Outline and Body Panes are affected -
just as described in
http://webpages.charter.net/edreamleo/outlines.html#resizing-panes. However from
the user perspective the current behaviour appears as though the command is only
partially successful. Since there are specific commands to contract/expand the
log pane, shouldn't the log and render panes also be affected by the
Window>Equal Sized Panes command?


I suppose so.  I would prefer to wait for Terry to finish his
pane-generalization code before dealing with this.
.. @+node:ekr.20110929074744.15449: *5* generalize show/hide/select gui elements commands
@nocolor-node

tab-cycle-next makes the following not so important

There is a relationship here with mouseless
programming.  It would seem that all visual elements, especially those
that may exist in multiple versions, must have a name or other
description suitable for generalized commands.

The user might want multiple rendering panes, especially if
one or more are locked.  Without a description, there is no way to
specify exactly what show/hide-rendering pane does.

I haven't forgotten the autocompleter docs.  I'll get to them next.
It looks like autocompletion would be the way to generalize the not-
very-effect commands that switch focus from one ui element to
another.  A related benefit is one generalized command might be more
convenient to use than the present flavors of (buggy) cycle-focus
commands.

In short, contemplating generalized windows leads us to generalized
select/delete/show/hide commands, based on autocompletion, that work
on various ui elements.  This looks like the next project. 
.. @+node:ekr.20110929074744.15499: *5* Allow more panes to be part of the free_layout "action" buttons
.. @+node:ekr.20101104191857.5820: *4* QWebView makes Leo a presentation tool
http://groups.google.com/group/leo-editor/browse_thread/thread/4ea2d3f7d2c68106#

Ville:

Create one QWebView window, zoom it in to have large fonts.

Create @button that converts current node containing restructuredtext to html,
and pushes that html to QWebView.

Voila', instant presentation tool. The webview window would be on projector, and
leo would be in your private computer. You can easily edit the text, or find new
interesting slides to present in privacy of your own screen.

.. @+node:ekr.20111019104425.15887: *4* Host the PyQt demo inside Leo
.. @+node:ekr.20111019104425.15888: *4* Support an openGL window in Leo
.. @+node:ekr.20111019104425.15892: *4* Buttons (Kent)
Enhance the button machinery to allow mixed case, spaces, colors.
Provide cascading rclick capability: rclick on an rclick list ...
.. @+node:ekr.20110605121601.18839: *4* Create color picker
createColorPicker
.. @+node:ekr.20110605121601.18843: *4* Fix problems with scim
@nocolor-node

http://groups.google.com/group/leo-editor/browse_thread/thread/59c1e5d6acaf4de0

I've some more information about the problems with accent previously
reported:
- I can confirm that they are caused by the interaction scim+leo (with
and without the qt plugin). If scim is not started leo works fine. If
scim is running the problems appear and are slightly different with
and without the qt plugin. The workaround is obvious: don't use leo
and scim at the same time :-)
- accents are not working in the qt plugin when scintilla is used. If
qt-use-scintilla=False I can write this:

àáä (the same for the rest of vowels)

but if qt-use-scintilla=True when I enter the same sequence in the
keyboard I get:

`aaa (the same for the rest of vowels)

- the problem with the ñ character (reported previously too) is only
present in the qt plugin (both with and without scintilla)
.. @+node:ekr.20110605121601.18837: *4* Cleanup
.. @+node:ekr.20110605121601.18838: *5* Remove or complete x.createBindings
.. @+node:ekr.20110605121601.18840: *5* Support cascade menu
leoQtFrame.cascade.
.. @+node:ekr.20110605121601.18841: *6* cascade
def cascade (self,event=None):

    '''Cascade all Leo windows.'''

    x,y,delta = 50,50,50
    for frame in g.app.windowList:

        w = frame and frame.top
        if w:
            r = w.geometry() # a Qt.Rect
            w.setGeometry(x,y,r.width(),r.height())

            # Compute the new offsets.
            x += 30 ; y += 30
            if x > 200:
                x = 10 + delta ; y = 40 + delta
                delta += 10
.. @+node:ekr.20110605121601.18842: *5* Should leoQtMenu.index do something?
.. @+node:ekr.20060824110846: *4* Add colorizing for cweb, rapidq
.. @+node:ekr.20050509085713: *3* Installer
.. @+node:ekr.20050328093147.1: *4* Report: improving installer
@killcolor
http://sourceforge.net/forum/message.php?msg_id=3064212
By: djsg

The following applies to Leo 4.3, which is in alpha as I write this. It describes
the LeoSetup routine that I submitted to Edward to solve the "can't find Python"
problem, and which Edward cleaned up for distribution.

I think a few further issues need attention. I noticed them while working on
the "can't find Python" problem, and deferred dealing with them. This appears
to me to be a good time to pick them up.

Before I start work on them, I would like to lay them out for your comment.
Are they pains in the first place? Are my proposals good enough, and do they
make sense?

Issue 1. LeoSetup still thinks Leo's user is an Administrator who owns the whole
machine.

For explanation, let's say that I log on as David to Windows 2000 or Windows
XP and install Leo 4.3. You then log out. You log in as Edward, and click Start,
pick Programs... you have no visible entry for Leo!

The current Setup routine allows no one but David to use Leo on this computer.
To make things worse, when I go to use Leo, I have to log in to Windows using
the account under which I installed it, which has Administrator rights to the
computer. In other words, I can't use Leo without operating the computer in
a mode that leaves it needlessly vulnerable to security violations.

Issue 2. LeoSetup allows only one copy of Leo on a given computer. 

LeoSetup assumes that you want Leo in C:\Program Files\Leo. The installer can
override that already. LeoSetup also goes to some trouble to set up the usual
click-to-open behavior for .leo files. That behavior is tied to the copy of
Python that was current when I ran LeoSetup, and tied to the copy of Leo that
was installed most recently.

Proposal: While LeoSetup should allow all accounts to share the Python code
for core Leo and its plug-ins, my guess is that we don't want to enforce that,
since Leo is a programmer's tool and the individual programmer will wish to
modify Leo and its pieces for the programmer's use.

Proposal Option 1. Setup should ask whether to install Leo for everyone or for
the installer's account only. If the answer to that question is "yes," Setup
should give the user a private copy of everything that comes with Leo -- the
only application shared should be the current Python, assuming that it is installed
for all users.

Python.org's installer for Python 2.4 allows the installed Python to work only
for the account that installed it. I found this in December and wrote code to
handle it, which I then commented out since the issue wasn't critical. I can
check a computer with a single-account installation of Python in order to figure
out how a single-account installation of Leo would have to handle the click-to-open
behavior.

Proposal Option 2. When LeoSetup finds Python installed for that single user,
it should ask whether to install Leo for the installer's account only. If the
answer to that question is "yes," Setup should give the user a private copy
of everything that comes with Leo and use the single-user installation of Python.
Why does this matter. If you need to test your plug-ins with different versions
of Python, this would make that easier.

Issue 3. LeoSetup always installs Python MegaWidgets ("Pmw"), even on computers
whose installed Python installation already includes it.

Proposal: put up a dialog box and ask whether Setup should install Pmw  I do
not know whether doing this is a good idea.

Issue 4. LeoSetup does not run without human intervention. This complicates
deploying Leo in multi-computer sites.

The message box that displays the path of the Python installation found is one
issue. I put it in to allow the installer to cross-check Setup's behavior. Since
nobody has complained about problems with the code I wrote to fix the problem
installing with Python 2.4 and Active Python, Setup need no longer force the
installer to review the message box's contents.

Proposal: The message box needs to time out after, say, 15 seconds. 

I last looked at the installer three months ago so I would have to look at the
rest of it for other barriers to automated installation.

Let me know what you think. I won't be able to start work for a week or so,
so there's no rush.

-- David
.. @+node:ekr.20070929125944: *4* Emulate Orange's download philosophy
@nocolor

http://sourceforge.net/forum/message.php?msg_id=4543089
By: billp9619

from the download page:

If it's the first time you hear about Python, this is the installation for you.
The packages includes complete Orange, Python, Windows Extensions for Python
(PythonWin), Numeric Python, Qt 2.2 non-commercial, PyQt, PyQwt and GraphViz.

Leo should copy this download philosophy.



.. @+node:ekr.20111018220642.15862: *3* Plugins
.. @+node:ekr.20111017132257.15882: *4* Study import_xml plugin
@language rest

http://groups.google.com/group/leo-editor/browse_thread/thread/b5c2982778a2df53

Provides commands (Alt-x) for importing and exporting XML from a Leo
outline. These commands are to XML what ``@auto-rst`` is to
reStructuredText.

``xml2leo`` imports an .xml file into the node following the currently
selected node.  ``leo2xml`` exports the current subtree to an .xml file
the user selects.

``xml_validate``, if executed on the top node in the
Leo xml tree, reports any errors in XML generation or DTD validation,
based on the DTD referenced from the XML itself.  If there's no DTD
it reports that as an error.

``leo2xml2leo`` takes the selected Leo subtree representing an XML file,
converts it to XML internally, and then creates a new Leo subtree from
that XML after the original, with 'NEW ' at the start of the top node's
name.  This updates all the headlines, so that the convenience only
previews (see below) are updated.  The original can be deleted if the
new subtree seems correct.

Conventions
===========

This is a valid XML file::

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE dml SYSTEM "dml.dtd">
    <?xml-stylesheet href="common.css"?>
    <dml xmlns='http://example.com/' xmlns:other='http://other.com/'/>
      <block type='example'>Here's <other:b>some</other:b> text</block>
    </dml>
    <!-- This is the last line -->

Note the processing instruction (xml-stylesheet), the DTD (DOCTYPE),
the trailing comment (after the closing tag), and the pernicious
mixed content (three separate pieces of text in the ``<block/>`` element).
These commands attempt to deal with all of this.

 - A top level Leo node is created to hold these top level parts.  Its
   headline is the basename of the file.
 - The xml declaration is placed in the body of
   this top level Leo node
 - Below that, in the same body text, appears a simple namespace map::

     http://example.com/
     other: http://other.com/
     ...

   i.e. the default namespace first, and then any prefixed name spaces.
 - Below that, in the same body text, appears the ``DOCTYPE`` declaration
 - Children are added to this top level Leo node to represent the
   top level elements in the xml file.  Headlines have the following
   meanings:

       - ``? pi-target some="other" __CHK`` - i.e. questionmark,
         space, name of processing instruction target, start of processing
         instruction content.  Only the questionmark, which indicates
         the processing instruction, and the first word, which indicates
         the processing instruction target, matter.  The remainder is just
         a convenience preview of the processing instruction content, which
         is the Leo node's body text.

       - ``# This is *really* imp`` - i.e. hash,
         space, start of comment content.  Only the hash, which indicates
         the comment, matters.  The remainder is just
         a convenience preview of the comment content, which
         is the Leo node's body text.

       - ``tagname name_attribute start of element text`` - i.e. the name
         of an element followed by a convenience preview of the element's
         text content.  If the element has a ``name`` attribute that's
         included at the start of the text preview.  Only the first word
         matters, it's the name of the element.

 - Element's text is placed in the Leo node's body.  If the element has
   tailing text (the ``" text"`` tailing the ``<other:b/>`` element
   in the above example), that occurs in the Leo node's body separated
   by the `tailing text sentinel`::

       @________________________________TAIL_TEXT_______________________________

 - Element's attributes are stored in a dict ``p.v.u['_XML']['_edit']``
   on the Leo node. ``'_XML'`` is the uA prefix for these commands, and
   ``'_edit'`` is used by the ``attrib_edit`` plugin to identify
   attributes it should present to the user for editing. The
   ``attrib_edit`` plugin **should be enabled** and its ``v.u mode``
   activated (through its submenu on the Plugins menu). The attribute
   edit panel initially appears as a tab in the log pane, although it
   can be moved around by right clicking on the pane dividers if the
   ``viewrendered`` and ``free_layout`` plugins are enabled. 
.. @+node:ekr.20111004090723.15495: *4* Finish leoOPML plugin
.. @+node:ekr.20111027143736.16557: *4* Study leo_screen
@nocolor-node

Ville mentioned leoremote for driving Leo from the command line.
There's also leoscreen, for driving the command line from Leo,
providing you use screen, which is probably unix/cygwin only.
.. @+node:ekr.20110930075237.15474: *3* Settings
.. @+node:ekr.20120516140545.9992: *4* Matt Wilkie
As for user interface, I'd love to see myLeoSettings with a checkbox
interface and filter bar at the top, and a feature to "merge or reset
from LeoSettings".

Or maybe something like Firefox's "about:config" would be better
suited (and probably faster to build).
.. @+node:ekr.20061011111007: *4* @bool autoload_most_recent_leo_file
@nocolor

http://sourceforge.net/forum/message.php?msg_id=3957908

> Is there a setting for autmoatically loading most recent file or files.

@color
.. @+node:ekr.20111109083738.9798: *3* Testing
.. @+node:ekr.20111105222316.9706: *4* Unit test: no unit tests omitted
@nocolor-node

Create a "registry" of unit tests.  Verify that unitTest.leo contains them all.
.. @+node:ekr.20111105222316.9707: *4* Unit test: importing a plugin changes nothing
@nocolor-node

Menu and plugin registry methods can fail if that *particular* unit test is running.
.. @+node:ekr.20111114151846.9856: *4* Unit test: verifies class relationships
.. @+node:ekr.20111114102224.9936: *5* << define class HighLevelInterface >>
class HighLevelInterface(object):

    '''A class to specify Leo's high-level editing interface
    used throughout Leo's core.

    The interface has two parts:

    1. Standard (immutable) methods that will never be overridden.

    2. Other (mutable) methods that subclasses may override.
    '''

    @others
.. @+node:ekr.20111114102224.9950: *6* ctor (HighLevelInterface)
def __init__ (self,c):

    self.c = c

    self.widget = None

    self.mutable_methods = (
        'flashCharacter',
        'toPythonIndex',
        'toPythonIndexRowCol',
        # 'toGuiIndex', # A synonym.
    )
.. @+node:ekr.20070302101344: *6* Must be defined in the base class (HighLevelInterface)

def disable (self):

    self.enabled = False

def enable (self,enabled=True):

    self.enabled = enabled

.. @+node:ekr.20111114102224.9935: *6* mutable methods (HighLevelInterface)
.. @+node:ekr.20111114102224.9946: *7* flashCharacter
def flashCharacter(self,i,bg='white',fg='red',flashes=3,delay=75):
    pass

.. @+node:ekr.20111114102224.9943: *7* toPythonIndex (HighLevelInterface)
def toPythonIndex (self,index):

    s = self.getAllText()
    return g.toPythonIndex(s,index)

toGuiIndex = toPythonIndex
.. @+node:ekr.20111114102224.9945: *7* toPythonIndexRowCol (BaseTextWidget)
def toPythonIndexRowCol(self,index):

    # This works, but is much slower that the leoQTextEditWidget method.
    s = self.getAllText()
    i = self.toPythonIndex(index)
    row,col = g.convertPythonIndexToRowCol(s,i)
    return i,row,col
.. @+node:ekr.20111114102224.9937: *6* immutable redirection methods (HighLevelInterface)
def appendText(self,s):
    if self.widget: self.widget.appendText(s)
def delete(self,i,j=None):
    if self.widget: self.widget.delete(i,j)
def deleteTextSelection (self):
    if self.widget: self.widget.deleteTextSelection()
def get(self,i,j):
    return self.widget and self.widget.get(i,j) or ''
def getAllText(self):
    return self.widget and self.widget.getAllText() or ''
def getInsertPoint(self):
    return self.widget and self.widget.getInsertPoint() or 0
def getSelectedText(self):
    return self.widget and self.widget.getSelectedText() or ''
def getSelectionRange (self):
    return self.widget and self.widget.getSelectionRange() or (0,0)
def getYScrollPosition (self):
    return self.widget and self.widget.getYScrollPosition() or 0
def hasSelection(self):
    # Take special care with this, for the benefit of LeoQuickSearchWidget.
    # This problem only happens with the qttabs gui.
    w = self.widget
    return bool(w and hasattr(w,'hasSelection') and w.hasSelection())
def insert(self,i,s):
    if self.widget: self.widget.insert(i,s)    
def replace (self,i,j,s):
    if self.widget: self.widget.replace(i,j,s)
def see(self,i):
    if self.widget: self.widget.see(i)
def seeInsertPoint (self):
    if self.widget: self.widget.seeInsertPoint()
def selectAllText (self,insert=None):
    if self.widget: self.widget.selectAllText(insert)
def setAllText (self,s):
    if self.widget: self.widget.setAllText(s)
def setBackgroundColor(self,color):
    if self.widget: self.widget.setBackgroundColor(color)
def setFocus(self):
    if self.widget: self.widget.setFocus()
def setForegroundColor(self,color):
    if self.widget: self.widget.setForegroundColor(color)
def setInsertPoint(self,pos):
    if self.widget: self.widget.setInsertPoint(pos)
def setSelectionRange (self,i,j,insert=None):
    if self.widget: self.widget.setSelectionRange(i,j,insert=insert)
def setYScrollPosition (self,i):
    if self.widget: self.widget.setYScrollPosition(i)
def tag_configure (self,colorName,**keys):
    if self.widget: self.widget.tag_configure(colorName,**keys)
.. @+node:ekr.20111114102224.9940: *6* other immutable methods (HighLevelInterface)
# These all use leoGlobals functions or leoGui methods.

def clipboard_append(self,s):
    s1 = g.app.gui.getTextFromClipboard()
    g.app.gui.replaceClipboardWith(s1 + s)

def clipboard_clear (self):
    g.app.gui.replaceClipboardWith('')

def getFocus(self):
    return g.app.gui.get_focus(self.c)

def rowColToGuiIndex (self,s,row,col):
    return g.convertRowColToPythonIndex(s,row,col)   

# def rowColToGuiIndex (self,s,row,col):
    # return self.widget and self.widget.rowColToGuiIndex(s,row,col) or 0 

set_focus = setFocus
.. @+node:ekr.20111114102224.9950: *5* ctor (HighLevelInterface)
def __init__ (self,c):

    self.c = c

    self.widget = None

    self.mutable_methods = (
        'flashCharacter',
        'toPythonIndex',
        'toPythonIndexRowCol',
        # 'toGuiIndex', # A synonym.
    )
.. @+node:ekr.20111114151846.9852: *5* mustBeDefined...
.. @+node:ekr.20111114151846.9850: *6* From baseTextWidget
.. @+node:ekr.20081031074455.3: *7* baseTextWidget.mustBeDefinedOnlyInBaseClass
mustBeDefinedOnlyInBaseClass = (
    'clipboard_append', # uses g.app.gui method.
    'clipboard_clear', # usesg.app.gui method.
)
.. @+node:ekr.20081031074455.4: *7* baseTextWidget.mustBeDefinedInSubclasses
mustBeDefinedInSubclasses = (
    'appendText',
    'delete',
    'deleteTextSelection',
    'get',
    'getAllText',
    'getFocus',
    'getInsertPoint',
    'getSelectedText',
    'getSelectionRange',
    'getYScrollPosition',
    'insert',
    'see',
    'seeInsertPoint',
    'setAllText',
    'setBackgroundColor',
    'setForegroundColor',
    'setFocus',
    'setInsertPoint',
    'setSelectionRange',
    'setYScrollPosition',
)

.. @+node:ekr.20081031074455.5: *7* baseTextWidget.mustBeDefined...
# These can be do-nothings
mustBeDefined = (
    'flashCharacter',
    'hasSelection',
    'replace',
    'rowColToGuiIndex',
    'selectAllText',
    'tag_configure',
    'toGuiIndex',
    'toPythonIndex',
    'toPythonIndexRowCol',
)
.. @+node:ekr.20111114151846.9851: *6* From leoBody
.. @+node:ekr.20081005065934.9: *7* leoBody.mustBeDefined
# List of methods that must be defined either in the base class or a subclass.

mustBeDefined = (
    'after_idle',
    'forceFullRecolor', # The base-class method is usually good enough.
    'initAfterLoad',
    'tag_configure', # used in qtGui.py.
)
.. @+node:ekr.20031218072017.3660: *7* leoBody.mustBeDefinedInSubclasses
mustBeDefinedInSubclasses = (
    # Birth, death & config.
    '__init__',
    'createBindings',
    'createControl',
    'setColorFromConfig',
    'setFontFromConfig'
    # Editors
    'createEditorLabel',
    'setEditorColors',
    # Events...
    'scheduleIdleTimeRoutine',
    # Low-level gui...(May be deleted)
    'getBodyPaneHeight',
    'getBodyPaneWidth',
    'hasFocus',
    'setFocus',
)
.. @+node:ekr.20061109102912: *7* define leoBody.mustBeDefinedOnlyInBaseClass
mustBeDefinedOnlyInBaseClass = (
    'getAllText',
    'getColorizer',
    'getInsertLines',
    'getInsertPoint',
    'getSelectedText',
    'getSelectionAreas',
    'getSelectionLines',
    'getYScrollPosition',
    'hasSelection',
    'oops',
    'onBodyChanged',
    'recolor',
    'recolor_now',
    'see',
    'seeInsertPoint',
    'selectAllText',
    'setInsertPoint',
    'setSelectionRange',
    'setYScrollPosition',
    'setSelectionAreas',
    'setYScrollPosition',
    'updateSyntaxColorer',
)
.. @+node:ekr.20111114151846.9853: *6* from leoFrame
.. @+node:ekr.20080429051644.1: *7* leoFrame.mustBeDefined
# List of methods that must be defined either in the base class or a subclass.

mustBeDefined = (

    # Icon bar convenience methods.    
    'addIconButton',
    'addIconRow',
    'clearIconBar',
    'createIconBar',
    'getIconBar',
    'getIconBarObject',
    'getNewIconFrame',
    'hideIconBar',
    'initAfterLoad',
    'initCompleteHint',
    'showIconBar',
)
.. @+node:ekr.20061109120726: *7* leoFrame.mustBeDefinedOnlyInBaseClass
mustBeDefinedOnlyInBaseClass = (

    'createFirstTreeNode', # New in Leo 4.6: was defined in tkTree.
    'initialRatios',
    'longFileName',
    'oops',
    'promptForSave',
    'scanForTabWidth',
    'shortFileName',

    # Headline editing.
    'abortEditLabelCommand',
    'endEditLabelCommand',
    'insertHeadlineTime',

    # Cut/Copy/Paste.
    'OnPaste',
    'OnPasteFromMenu',
    'copyText',
    'cutText',
    'pasteText',

    # Status line convenience methods.
    'createStatusLine',
    'clearStatusLine',
    'disableStatusLine',
    'enableStatusLine',
    'getStatusLine',
    'getStatusObject',
    'putStatusLine',
    'setFocusStatusLine',
    'statusLineIsEnabled',
    'updateStatusLine',
)
.. @+node:ekr.20061109120704: *7* leoFrame.mustBeDefinedInSubclasses
mustBeDefinedInSubclasses = (
    #Gui-dependent commands.
    'cascade',
    'contractBodyPane',
    'contractLogPane',
    'contractOutlinePane',
    'contractPane',
    'equalSizedPanes',
    'expandLogPane',
    'expandPane',
    'fullyExpandBodyPane',
    'fullyExpandLogPane',
    'fullyExpandOutlinePane',
    'fullyExpandPane',
    'hideBodyPane',
    'hideLogPane',
    'hideLogWindow',
    'hideOutlinePane',
    'hidePane',
    'leoHelp',
    'minimizeAll',
    'resizeToScreen',
    'toggleActivePane',
    'toggleSplitDirection',
    # Windowutilities...
    'bringToFront',
    'deiconify',
    'get_window_info',
    'lift',
    'update',
    # Config...
    'resizePanesToRatio',
    'setInitialWindowGeometry',
    'setTopGeometry',
)
.. @+node:ekr.20111114151846.9854: *6* from leoTree
.. @+node:ekr.20081005065934.7: *7* leoTree.mustBeDefined
# List of methods that must be defined either in the base class or a subclass.

mustBeDefined = (
    'initAfterLoad', # New in Leo 4.6.
    'treeSelectHint', # New in Leo 4.6.
)
.. @+node:ekr.20061109164512: *7* leoTree.mustBeDefinedOnlyInBaseClass
mustBeDefinedOnlyInBaseClass = (
    # Getters & setters.
    'editPosition',
    'getEditTextDict',
    'setEditPosition',
    # Others.
    'endEditLabel',
    # 'expandAllAncestors', # Now defined in Commands class.
    'injectCallbacks',
    'OnIconDoubleClick',
    'onHeadChanged',
    'onHeadlineKey',
    'updateHead',
    'oops',
)
.. @+node:ekr.20061109164610: *7* leoTree.mustBeDefinedInSubclasses
mustBeDefinedInSubclasses = (
    # Colors & fonts.
    'getFont',
    'setFont',
    'setFontFromConfig ',
    # Drawing & scrolling.
    'drawIcon',
    'redraw_now',
    'scrollTo',
    # Headlines.
    'editLabel',
    # 'setEditLabelState',
    # Selecting.
    # 'select', # Defined in base class, may be overridden in do-nothing subclasses.
)
.. @+node:ekr.20111114151846.9855: *6* from leoGui
.. @+node:ekr.20061109211054: *7* leoGui.mustBeDefinedOnlyInBaseClass
mustBeDefinedOnlyInBaseClass = (
    'guiName',
    'oops',
    'setScript',
    'widget_name',
)
.. @+node:ekr.20061109211022: *7* leoGui.mustBeDefinedInSubclasses
mustBeDefinedInSubclasses = (
    # Startup & shutdown
    'attachLeoIcon',
    'center_dialog',
    'color',
    #'createComparePanel',          # optional
    'createFindTab',
    # 'createKeyHandlerClass',
    'createLeoFrame',
    'createRootWindow',
    'create_labeled_frame',
    'destroySelf',
    #'eventChar',
    #'eventKeysym',
    'eventWidget',
    # 'eventXY',
    # 'finishCreate', # optional.
    # 'getFontFromParams', # optional
    # 'getFullVersion', # optional.
    'getTextFromClipboard',
    'get_focus',
    'get_window_info',
    'isTextWidget',
    # 'keysym',
    'killGui',
    # 'makeScriptButton', # optional
    'recreateRootWindow',
    'replaceClipboardWith',
    'runAboutLeoDialog',
    'runAskLeoIDDialog',
    'runAskOkCancelNumberDialog',
    'runAskOkDialog',
    'runAskYesNoCancelDialog',
    'runAskYesNoDialog',
    'runMainLoop',
    'runOpenFileDialog',
    'runSaveFileDialog',
    'set_focus',
    #'setIdleTimeHook',             # optional       
    #'setIdleTimeHookAfterDelay',   # optional
)
.. @+node:ekr.20100131161507.6303: *4* Unit test: all commands have docstrings
# Just make the test.  It doesn't have to pass.
.. @+node:ekr.20110527225107.18351: *3* Vague
@language rest

**Important**: These items are not scheduled for any release. They will be done
only if there are specific requests for them.
.. @+node:ekr.20120516140545.9993: *4* Code cleanups
.. @+node:ekr.20111010093113.15548: *5* Lighten Leo's code base; remove wrapper layers
@nocolor-node

Almost from day one, Leo has defined gui base classes in the core, and
subclasses in gui plugins.

I plan to continue that organization, but I would like to remove some of the
wrapping layers if possible. The present scheme has one or two too many
redirection layers, and they are more of a nuisance than a help.

One idea would be to define **interface classes** that define the desired api's.
Unit tests could test that subclass implements the interface class, without
having to resort to quite as much error-prone machinery as at present.
.. @+node:ekr.20111021035504.9467: *5* Play with PyQt Qtest framework
http://groups.google.com/group/leo-editor/browse_thread/thread/b851e7d9855a57c2

http://www.voom.net/pyqt-qtest-example
.. @+node:ekr.20120205022040.15412: *5* Refactor the key code (Vague)
@nocolor-node
    
* Define k factory methods:
    
    k.makeKeyStroke(user_setting_string)
    k.makeKeyStrokeFromData(data)
    k.makeShortcutInfo(...)

* Refactor the Qt input code so it calls k.makeKeyStrokeFromData(data).
  This will require untangling the input code from event handling code.
.. @+node:ekr.20120226183512.10202: *5* Use QSignalSpy?
QSignalSpy: doesn't exist on PyQt?
.. @+node:ekr.20120515193246.10089: *4* Features
.. @+node:ekr.20111019104425.15895: *5* LeoFS (Kent)
- create a Leo implementation of pyfilesystem
http://packages.python.org/fs/implementersguide.html

.. @+node:ekr.20060227123536: *5* Tiddlywiki and related comments about rendering body text (Mulder)
@nocolor
http://sourceforge.net/forum/message.php?msg_id=3578252
By: bwmulder

I have been thinking for a while that it ought to be possible to somehow  to
unite Leo with wiki features (my thinking is still vague at this point).

If you look at systems like Tiddlywiki (http://www.tiddlywiki.com/) you will
find that they already pretty much provide all the formatting features mentioned
in the article.

MoinMoin, another wiki (http://moinmoin.wikiwikiweb.de), has started to use
a graphical interface for editing in the latest version.

Maybe Leo can be split up into three components:

1. A storage component is responsible for storing nodes. Currently, this is
just memory, but databases like shelve, Zope or sqllite should also be possible.

2. The control component is responsible for converting from the internal format
to external files which can be processed by existing compilers, searching within
a document, and the like.

3. A display component is responsible for interfacing with the user. If can
be TK, but it can also be something like the Tiddlywiki interface, which immediately
shows the formatting applied to text.

I don't know much about javascript, so I would have to learn more about this
language before doing anything in this direction.

As an intermediate step, maybe we could allow mixing RST processing with regular
program text.  Leo would produce two documents out of a source file: a version
for the compiler in plain ascii, and an HTML file for reading the source.
.. @+node:ekr.20120226180525.10191: *5* Run unit tests interactively?
@nocolor-node

Getting value from Bret Victor's video

http://groups.google.com/group/leo-editor/browse_thread/thread/9e1785ba4f57faf8

Thus, to associate code with unit tests, we need only create a
convention for associating source code with nodes.  But clones make
this trivial to do!

- @interactive-unit-tests
 - @itest
   - @test spam
   - (clone of) spam

This is all we would need to "declare" that @test spam should be run
whenever the spam node changes!

These are just first thoughts, made up as I am writing this post.  But
clearly, Leo can do more in this area.
.. @+node:ekr.20111019104425.15863: *5* Use pygments for syntax coloring?
This has essentially no chance of improving Leo
.. @+node:ekr.20110529115328.18238: *5* Emacs related: 5
I'll do these if and and only if somebody asks for them.
.. @+node:ekr.20110529104352.18248: *6* Complete k.universalDispatcher
.. @+node:ekr.20110529104352.18249: *6* Complete number-to-register command
.. @+node:ekr.20031218072017.753: *6* Emacs comint-mode
@nocolor

The improved Execute Script command does most of this

Michael Manti
mmanti@mac.com

P.S. I think a feature that could make Leo *the* IDE for developing in 
interpreted languages is something like the (X)Emacs comint-mode.el for 
interacting with the shell and interpreters.

comint-mode.el serves as the basis for interactive modes for a number of
languages--OCaml, Haskell, SML, among them. It allows for editing expressions in
one buffer and triggering their evaluation in another buffer that has an
interpreter running in it, along with entering commands in the interpreter
buffer and moving back and forth through the history of their evaluation.

Imagine being able to highlight a node in Leo, and have all the code in it and
its children evaluated in an interpreter running in a separate window or pane,
much as Leo can open a Python shell now. Users of those languages could build
plug-ins specific to their language atop that layer, and the @language directive
could activate that. I think that would be very cool.
.. @+node:ekr.20071004120359.2: *6* expand-region-abbrev
See: regionalExpandAbbrev.

You may wish to expand an abbrev with a prefix attached; for example, if `cnst'
expands into `construction', you might want to use it to enter `reconstruction'.
It does not work to type recnst, because that is not necessarily a defined
abbrev. What you can do is use the command M-' (abbrev-prefix-mark) in between
the prefix `re' and the abbrev `cnst'. First, insert `re'. Then type M-'; this
inserts a hyphen in the buffer to indicate that it has done its work. Then
insert the abbrev `cnst'; the buffer now contains `re-cnst'. Now insert a
non-word character to expand the abbrev `cnst' into `construction'. This
expansion step also deletes the hyphen that indicated M-' had been used. The
result is the desired `reconstruction'.

If you actually want the text of the abbrev in the buffer, rather than its
expansion, you can accomplish this by inserting the following punctuation with
C-q. Thus, foo C-q , leaves `foo,' in the buffer.
.. @+node:ekr.20060628103226.3: *6* Make sure repeat counts work on basic editing commands
.. @+node:ekr.20111010122531.15568: *5* @render-rest, @render-html trees
@language rest

The free_layout and viewrendered plugins are a huge step forward.  But
the lighter/heavier distinction suggests a new way to use them.

Suppose Leo supports @render-rest or @render-html.

This means that all nodes in the tree will have the body pane become a
rendering pane for rST or html.

Imagine LeoDocs completely rendered at all times.

Of course, for specific purposes, say in Leo's scripting chapter, we
might want to override these rendering directives (which should be
allowed in headlines too) with @no-render.

The point is that having *both* the original text *and* the rendered
text be visible is often too heavy: the user usually does not want to
know about the sources: the rendering is good enough.

I suppose for sophisticated users, something like show/hide-body pane
would be good commands to have, but that doesn't matter: those
commands to not increase the burden on the user while she is reading
the (rendered) docs.
.. @+node:ekr.20111011175652.15696: *4* Register a domain name like leo-editor.org
.. @+node:ekr.20130821062332.11232: ** Scripts
.. @+node:ekr.20130503155210.24826: *3* Script: Add Windows handler for .leo files
# https://groups.google.com/forum/?fromgroups=#!searchin/leo-editor/leo$20script/leo-editor/ANPuhuEIU9c/8lgid9MNKkAJ

@language python
@tabwidth -4

'''Tell Windows how to handle .leo files, enables double clicking on them to open.

To run: in Leo make this the active node and press [Ctrl-B] (execute-script)

It opens a command shell and uses `assoc` and `ftype` commands to inform Windows
where python.exe and the Leo launch script is. It's the equivalent of:

    assoc .leo=Leo.File
    ftype Leo.File="B:\Python27\pythonw.exe" "B:\apps\leo-editor\launchLeo.py" "%1" %*   
       
Requires elevated User Account Control (UAC) priviliges.
See http://superuser.com/questions/88491/force-cmd-exe-to-run-as-admin/
'''

pyexe = g.sys.executable
leo = g.os_path_finalize_join(g.computeLeoDir(), '../launchLeo.py')

tmp = g.os.environ['TEMP']

assoc_cmd = 'assoc .leo=Leo.File'
ftype_cmd = 'ftype Leo.File="{0}" "{1}" "%1" %*'.format(pyexe, leo)

g.es(leo)
g.es(pyexe)

g.es(tmp)
g.es(assoc_cmd)
g.es(ftype_cmd)

from subprocess import Popen
Popen('start "Shell from Leo" cmd.exe /k "{0} && {1}" '.format(assoc_cmd, ftype_cmd),

    cwd=tmp, shell=True)
.. @+node:ekr.20130503155210.24827: *3* Console script: Install Leo from scratch on Windows
@language batch

mkdir X:\testing
pushd X:\testing

wget -O apt.exe --no-clobber http://download.osgeo.org/osgeo4w/release/apt/apt-r1193M.exe
SET OSGEO4W_ROOT=%~dp0\root
apt setup
apt update
apt install pyqt4 sip

call root\osgeo4w.bat

wget --no-check-certificate http://gist.github.com/maphew/5393935/raw/install-pip.py
python install-pip.py GO
python install-pip.py GO

pip install -i https://testpypi.python.org/pypi leo-editor

python apps\Python27\Scripts\leo
.. @+node:ekr.20130806072439.20398: *3* Bat file launchers for nightly builds
From: Matt Wilkie <maphew@gmail.com>

Inspired by the recent problem Nils reported with the 4.10 final installer,
I've built a batch file to make running the development snapshots a little
easier, attached. Here is the header::

    @echo
    :: A batch file which generates other batch files to run the Leo Editor,
    :: adapted for the local machine. Optionally, it will also set the Windows
    :: filetype and association so .leo files can be opened from Explorer.
    ::
    :: It needs to live in the same folder as "launchLeo.py"
    ::
    :: Open Source X/MIT License
    :: initial version * 2012-Dec-13 * matt wilkie <maphew@gmail.com>

Feel free to use, modify or discard as you see fit.

Although it can register the filetype and association, removing them is
left as an exercise for the reader (`assoc /? && ftype /?`); maybe later.
.. @+node:ekr.20130806072439.20399: *4* Re: Bat file launchers for nightly builds
From: Matt Wilkie <maphew@gmail.com>

Re "@", that instructables says the same thing, to my reading. SS64 might
be a better reference site: http://ss64.com/nt/echo.html. Just ponder this:
why do we commonly use "@echo off" instead of "echo off" ?

Re: "\\\\in\\\\path" not working on XP for you. Interesting, I've used it on XP
myself without troubles many times. I did turn up an unanswered question on
Stack Overflow about the same thing with double-double slashes:
http://stackoverflow.com/questions/729151/double-backslash-not-work

So It looks like the safe thing to do is strip the extra slash, even if it
does play havoc with most editor's syntax highlighting of variables.
.. @+node:ekr.20130806072439.20411: *4* Re: Bat file launchers for nightly builds
@nocolor

From: Terry Brown <terry_n_brown@yahoo.com>

On Thu, 13 Dec 2012 23:59:05 -0800
Matt Wilkie <maphew@gmail.com> wrote:

> Hi Terry,
> 
> Inspired by the recent problem Nils reported with the 4.10 final installer,
> I've built a batch file to make running the development snapshots a little
> easier, attached. Here is the header:

Edward - I haven't tested this batch file to register the .leo
extension and make batch files to run leo in Windows, not using
windows, but it looks useful. Here's the current contents of the Leo
root dir:

bzr-manifest.txt         leo_to_html.xsl  pylint-leo.py
INSTALL.TXT              LICENSE.TXT      README.TXT
launchLeo.py             Makefile         setup.py
leo                      PKG-INFO.TXT     stand_along_globals.leo
leo.nsi                  profileLeo.py
leoStandAloneGlobals.py  pylint-leo.bat

so it seems adding another file, create-leobat.bat, can't hurt, do you
agree?

On the snapshot download page I'll add pointer to the create-leobat.bat
for windows users and I guess it should go in the docs. somewhere also.

.. @+node:ekr.20130806072439.20412: *4* Re: Bat file launchers for nightly builds
@nocolor

From: gatesphere <gatesphere@gmail.com>


Hi Matt,

I've responded on the Gist too, but I'll copy what I had here.

On 5/5/2013 5:19 PM, Matt Wilkie wrote:
> Do you remember why you needed to use `%%1` in place of `%%*` ?
>
> The former will only pass the 1st parameter while the 2nd will pass 
> everything. So when using `%%1` the second and further files or 
> parameters will be ignored. I didn't come up with a scenario where 
> that is needed or an improvement, but perhaps I'm missing a use case 
> were it is(?)
>

L32: Good question why I did that... no clue, really. It works, though, 
for my purposes.|%%*|is probably correct, and I will revise this.

L34-35: Google says 
otherwise:http://www.instructables.com/id/Slightly-More-Advanced-Basic-Batch/step2/ECHO-OFFON-Command/
That being said, I did test this both with and without the@echo 
<https://gist.github.com/echo>off line... and it only worked with 
the@echo <https://gist.github.com/echo>off line. At least on my systems 
(2 win xp, 1 win 7 64).

L21: It was complaining on my WinXP boxes, but that could be a security 
setting. Both of my WinXP boxes are the property of my employer, and 
they have some pretty crazy security protocols in place. Not sure if 
that has anything to do with it, but my WinXP boxes didn't like the 
extra slash at all.

-->Jake

.. @+node:ekr.20130803073926.12442: ** Waiting
- Waiting for answer re ubuntu splashscreen
    http://qt-project.org/forums/viewthread/30837/
    createSplashScreen
    
- Waiting for answer to solarized question:
    http://qt-project.org/forums/viewthread/30838/
    https://groups.google.com/forum/#!topic/leo-editor/W1_LVrQxdwQ
.. @-all
.. @-leo
