Think of it as my experiment to see how you write plugins for the gui
part directly, and a little qt finger excercise at Qt (that won't
break anything). Note that fun little plugins like this are very easy
to create - just draw a QWidget in UI designer, connect the signals,
and slap it into the tab of leo log pane by:
tabw = c.frame.top.tabWidget
wdg = LeoQuickSearchWidget(c,tabw)
tabw.addTab(wdg, "QuickSearch")
Installation is awkward and messy, I just wanted to get it started quickly:
- Open leo with qtGui,
- Edit a node, add text g.insqs(c), select the text, run "execute
script" from menu
- Observe how you have "QuickSearch" tab in the log pane. Start
entering text, and the list of headline matches is updated in real
time.
- Click on a match to jump to the node directly
Again, screenshot attached. It's obviously incomplete, too sparse etc.
Also, ignore the horrible font.
--
Ville M. Vainio
http://tinyurl.com/vainio
Many thanks for this work. It shows, I think, the advantages of not
being bound by Leo's core.
There is a useful tension between your approach and mine. It reminds
me of the way LeoUser influenced Leo. He created the temacs plugin in
a week or so, and I spent a year making the minibuffer and its
commands part of Leo.
What I am trying to say is that this kind of work is an elegant
reminder that things don't always have to be as difficult (at least at
first) as I end up making them :-)
Edward
> My intuition is beginning to yell at me that you are on to something
> important, something that would be a big change in the way I think
> about programming. These kinds of intuitions are seldom wrong.
My thoughts are running toward making Leo more like Squeak. Squeak
objects build up their behaviors through composition. I think of it
as a packaging issue. Perhaps another grand reorganization is coming,
but first I need some effective principles...
Edward
I don't appreciate the subtleties, but that doesn't prevent my having an opinion
about vim bindings that I've been looking for an opportunity to interject.
Vim users will NOT use Leo in any kind of Vim mode.
There, I said it.
A Vim user will become frustrated in moments by any environment that is
somewhat Vim-like but doesn't support _all_ of Vim.
A Vim user will continually try to enter command mode, needs all the extension
capability, etc.
A Vim user is familiar with at least 2 editing environments, Vim and standard.
(standard meaning gedit, joe, notepad, etc)
Learning a hybrid will involve more effort than editing in standard mode
A Vim user will leverage the Leo capability to open nodes or files in
Vim, thus combining the full bore power of each.
Vim bindings in Leo will only appeal to Leo users seeking to reduce mouse
usage, which is great, but a small audience compared to Vim users.
So, Vim bindings in Leo are great, but they are an edge case, should not
impede core architectural improvements.
These opinions are in no way humble, they are _correct_
:-}
<ducks>
> What I am trying to say is that this kind of work is an elegant
> reminder that things don't always have to be as difficult (at least at
> first) as I end up making them :-)
I guess the main problem is that Leo tries to do too much stuff in the core.
As I see it, the core should only do core stuff, and shouldn't attempt
to "drive" the GUI. It's the GUI's problem to do all the gory stuff
and tell the core what the user wants to do. The core does not need to
know that the GUI has these tabs open, or know anything about the tabs
in the first place. As a relevant example, there is no reason to have
any "find" functionality in core. The core may publish an iterator
that return (position, line number) pairs, but it shouldn't matter how
the GUI uses that stuff. Nor does the core need no know anything about
bindings - it should just relay the "bind" commands to GUI (when it
finds that stuff in @settings), and the GUI can use that information
as it sees fit. Keypresses are a GUI/view artifact, not core
functionality.
This is the crux of my recent complaints about the core not following
mvc paradigm to a sufficient extent. It makes the dependency between
core and gui too tight, and makes the codebase too complex and
unpenetrable to new developers (and possibly also shows why previous
gui plugin projects were not finished).
> A Vim user will become frustrated in moments by any environment that is
> somewhat Vim-like but doesn't support _all_ of Vim.
Your statement doesn't disturb me in the least. In fact, it's a spur
to make simplify key bindings significantly.
I'm not happy with vim bindings, not for user-centric reasons, but
because I can't understand all the code in enough detail to improve
it. This just cries out for improvement.
Ville and I are squabbling over details. Imo, our vision is very
similar: to make Leo more powerful and flexible by clearing away
rubbish that adds nothing but frustration.
Edward
> I guess the main problem is that Leo tries to do too much stuff in the core.
>
> As I see it, the core should only do core stuff, and shouldn't attempt
> to "drive" the GUI.
I think you misunderstand what I meant by "drive":
Leo does, in fact, have a perfectly reasonable overall organization.
The core code has *nothing* to do with gui details. It may not look
that way, but it's true nonetheless.
In leoEditCommands.py you will see lots of calls to w.setAllText,
w.getInsertionPoint, etc. These are not calls to gui widgets
directly, they are calls to wrapper classes. For qt, they are calls
to methods of leoQtBody. Thus, Leo's core knows only about an
abstract text widget.
> It's the GUI's problem to do all the gory stuff.
And that's exactly where all the gory stuff happens.
In other words only the gui base classes are part of Leo's core. The
tkinter classes are in effect an official Tk plugin that just happens
to reside in LeoPyRef.leo. They are *not* part of Leo's core.
> The core does not need to know that the GUI has these tabs open,
> or know anything about the tabs in the first place.
True, but in fact the core doesn't know.
> As a relevant example, there is no reason to have
> any "find" functionality in core.
Wrong. Take a look at leoFind.py. There is lots of code there that
was difficult to get correct and works for any gui that supports its
interface. This is true core code.
> The core may publish an iterator
> that return (position, line number) pairs, but it shouldn't matter how
> the GUI uses that stuff.
Again, you are correct, but your implication is wrong. The classes in
leoNodes.py know nothing about how they are used. In fact, these
classes know nothing about Leo at all, not even what commander they
are in. These classes could be used, without modification, in any
other editor.
> Nor does the core need no know anything about
> bindings - it should just relay the "bind" commands to GUI (when it
> finds that stuff in @settings), and the GUI can use that information
> as it sees fit.
In essence, that's what happens. See c.bind. It calls w.bind, where
w will be leoQtBody when the qt plugin is running.
You keep using the word "just". Take a look at leoConfig.py. It's
complicated because it has a big, complex job to do. This work simply
must be in the core: it has nothing to do with guis and it would be
unbearable to duplicate this code.
> Key presses are a GUI/view artifact, not core functionality.
True, but key *bindings* are one of Leo's great strengths. Because of
Tk awfulness, some of Leo's core is messed up. I would indeed like to
clean this up, and "demoting" Tk to a plugin might highlight where
that cleanup can occur.
But that's a big project, and I'd rather not start that now...
> This is the crux of my recent complaints about the core not following
> mvc paradigm to a sufficient extent. It makes the dependency between
> core and gui too tight.
To the first approximation, there is *no* dependency between the core
and the gui, provided that you realize that the gui subclasses in
LeoPyRef.leo are not part of the core.
> and makes the codebase too complex and impenetrable to new developers
The Tk related stuff is indeed complex, mainly because there is no
official Tk.Tree widget.
I'll admit that the gui base classes might be simplified, but even now
the classes needed to implement, say, the qt minibuffer follow your
prescriptions *exactly*. A leoQtMinibuffer class, for example, needs
to know exactly nothing about how the minibuffer is used. It simply
needs to implement the methods of the base leoKeys class:
Code-->Gui Base classes-->@thin leoKeys.py-->class
keyHandlerClass-->Minibuffer (keyHandler)
> (and possibly also shows why previous gui plugin projects were not finished).
The wx plugin didn't get finished because the wx people kept blowing
off my complaints.
Edward
> Leo does, in fact, have a perfectly reasonable overall organization.
> The core code has *nothing* to do with gui details. It may not look
> that way, but it's true nonetheless.
>
> In leoEditCommands.py you will see lots of calls to w.setAllText,
> w.getInsertionPoint, etc. These are not calls to gui widgets
> directly, they are calls to wrapper classes. For qt, they are calls
> to methods of leoQtBody. Thus, Leo's core knows only about an
> abstract text widget.
There is already a dependency when the core knows the abstract text
widget. Text widget is assumed to work in a certain way / whatever.
>> It's the GUI's problem to do all the gory stuff.
>
> And that's exactly where all the gory stuff happens.
>
> In other words only the gui base classes are part of Leo's core. The
> tkinter classes are in effect an official Tk plugin that just happens
> to reside in LeoPyRef.leo. They are *not* part of Leo's core.
In an ideal MVC appoarch, there would not even be those base classis.
Things in core would be dispatched by notifications like
positionEdited, treeModified that the GUI could subscribe if
interested. However, I don't think this is a huge problem at this
point since much of the gui is already working.
>> The core does not need to know that the GUI has these tabs open,
>> or know anything about the tabs in the first place.
>
> True, but in fact the core doesn't know.
>
>> As a relevant example, there is no reason to have
>> any "find" functionality in core.
>
> Wrong. Take a look at leoFind.py. There is lots of code there that
> was difficult to get correct and works for any gui that supports its
> interface. This is true core code.
It may work well - I don't have the time to investigate now. Perhaps
it's gui code that can be shared by different guis, but that doesn't
make it necessary "core" code.
Or perhaps it's my attitude problem against subclassing, which I
consider to be generally bad idea ;-).
>> The core may publish an iterator
>> that return (position, line number) pairs, but it shouldn't matter how
>> the GUI uses that stuff.
>
> Again, you are correct, but your implication is wrong. The classes in
> leoNodes.py know nothing about how they are used. In fact, these
> classes know nothing about Leo at all, not even what commander they
> are in. These classes could be used, without modification, in any
> other editor.
Yeah, and those classes are what I consider to be the essence of
"core". They are stuff that empower the gui, without requiring the gui
to do or implement anything.
>> Nor does the core need no know anything about
>> bindings - it should just relay the "bind" commands to GUI (when it
>> finds that stuff in @settings), and the GUI can use that information
>> as it sees fit.
>
> In essence, that's what happens. See c.bind. It calls w.bind, where
> w will be leoQtBody when the qt plugin is running.
Ok, great.I was mislead by the fact that we check the binding from the core.
> You keep using the word "just". Take a look at leoConfig.py. It's
> complicated because it has a big, complex job to do. This work simply
> must be in the core: it has nothing to do with guis and it would be
> unbearable to duplicate this code.
Yeah, that's again what I consider to be rightfully in the core.
>> Key presses are a GUI/view artifact, not core functionality.
>
> True, but key *bindings* are one of Leo's great strengths. Because of
> Tk awfulness, some of Leo's core is messed up. I would indeed like to
> clean this up, and "demoting" Tk to a plugin might highlight where
> that cleanup can occur.
It doesn't matter whether the strength is located in core or gui side.
Also, I don't think it will matter what we do with Tk one year from
now, since nobody will probable be using it ;-). Qt will probably be
the last GUI leo needs to implement, since it's not going anywhere
anytime soon.
>> (and possibly also shows why previous gui plugin projects were not finished).
>
> The wx plugin didn't get finished because the wx people kept blowing
> off my complaints.
There was also a gtk plugin that fell under the radar a while ago
(that I never saw running).
> There is already a dependency when the core knows the abstract text
> widget. Text widget is assumed to work in a certain way / whatever.
Sure. But do you have a better way? Do you want to rewrite all of
leoEditCommands.py in the qtGui plugin?
> It may work well - I don't have the time to investigate now. Perhaps
> it's gui code that can be shared by different guis, but that doesn't
> make it necessary "core" code.
It's absolutely not gui code. It's code that uses gui code.
> Or perhaps it's my attitude problem against subclassing, which I
> consider to be generally bad idea ;-).
Here we have the heart of the matter. I'll explain in a separate
thread called Leo's MVC architecture.
> Yeah, and those classes [in leoNodes.py] are what I consider to be the essence of
> "core".
They are Leo's model.
>> You keep using the word "just". Take a look at leoConfig.py. It's
>> complicated because it has a big, complex job to do. This work simply
>> must be in the core: it has nothing to do with guis and it would be
>> unbearable to duplicate this code.
>
> Yeah, that's again what I consider to be rightfully in the core.
leoConfig.py is part of Leo's core. It's part of the controller, not the model.
> It doesn't matter whether the strength is located in core or gui side.
It matters a great deal. If in the gui side, it must be duplicated by
every gui. If in the core, it only gets done once, in a standard,
testable way. More in the MVC thread.
> There was also a gtk plugin that fell under the radar a while ago
> (that I never saw running).
That wasn't my project. It failed because Bob's boss told him to stop
working on Leo.
Edward
--------------------------------------------------------------------
Edward K. Ream email: edre...@gmail.com
Leo: http://webpages.charter.net/edreamleo/front.html
--------------------------------------------------------------------
> Sure. But do you have a better way? Do you want to rewrite all of
> leoEditCommands.py in the qtGui plugin?
If it was up to me, I would see which ones can be made to work well
with the features where an obvious implementation exists, and let the
other ones break (macros come to mind, if we disconnect basic editing
keystrokes from core). The broken ones can then be fixed when time is
due, but they should not be "critical" - scintilla is a popular text
widget, and people seem to use it quite happily.
>> It doesn't matter whether the strength is located in core or gui side.
>
> It matters a great deal. If in the gui side, it must be duplicated by
> every gui. If in the core, it only gets done once, in a standard,
> testable way. More in the MVC thread.
I don't think there needs to be more than one GUI with full leo
functionality (and that's the Qt one, obviously ;-), so I'm not too
worried about this. Other GUI's can be implemented as little toy UI's
for special-purpose uses only using Leo's model, as I have done with
qleolite and mobileleo.
>> There was also a gtk plugin that fell under the radar a while ago
>> (that I never saw running).
>
> That wasn't my project. It failed because Bob's boss told him to stop
> working on Leo.
Of course. My point was - I was able to implement a prototype using
only leo's model, probably *because* I didn't have time to look into
all the intricacies of creating a full-blown plugin. There is a large
intimidation factor in a thick api, even if it has grown out of
necessity. I was just thinking that "ok, I have a tree widget, an
editor and leo's model, so all I need is to connect them - the rest is
extra". What you need to motivate kids these days is to give them
something they can pick up and start hacking immediately. ;-)
Clearly, the best analysis of leo's architecture comes from you (since
you understand the architecture 5400% better than I do), but I hope to
raise some questions at least. I'm a big advocate of simplicity, and I
freely admit that given the choice between simplicity and features, I
would be the first one to throw away features.
> In the past, I have pointed this out and have offered to work with a
> "Python guru" to update the existing functions (side effect?) or
> develop new ones. No one has volunteered.
Oh. This offer got lost on my e-desk. I'm certainly willing to help.
Please break the work down into small tasks that we can do one at a time.
You can be sure that whatever work we do won't get lost in the qt gui world.
Edward