> This thread will summarize everything that users and developers should
> know about autocompletion and calltips.
Excellent, thanks for doing this.
Cheers -Terry
> Later posts will discuss...detailed instructions for using the autocompleter. This will
> discuss the effect of several other autocompletion-related settings.
Here they are, but first some notes:
1. Notice the dog that is not barking. There is no discussion of the
setting @bool use_codewise because that setting is no longer used!
Indeed, Leo *always* attempts Leo-specific (eval-oriented)
completions, and falls back on codewise (ctags) conversions if there
are none. I'll remove this setting soon from leoSettings.leo.
2. The follow docs are not entirely complete: I'll fold in some
details from the existing docs. However, the following docs discuss
the most important features of autocompletion. A later post will
discuss in detail how the code works.
All corrections an completions welcome. Without further ado, the
following is my best attempt at explaining how autocompletion actually
works...
----------------------------------------------------------------
Leo's autocompletion suggests **completions**, text may be valid in a given
point, or **context** in source code. For example, suppose the context is::
os.path.s
That is, suppose the cursor follows ``os.path.s`` in the body pane. The valid
completions are all the members of Python's os.path module whose names
start with 's',
namely::
samefile
sameopenfile
sep
split
splitdrive
splitext
splitunc
stat
supports_unicode_filenames
sys
Starting autocompletions
========================
There are two ways to have Leo show autocompletions, manually and automatically.
You can use both at the same time.
**Manual autocompletion**: Leo will show autocompletions whenever you execute
the auto-complete-force (ctrl-space) command.
**Automatic autocompletion**: If (automatic) autocompletion is
enabled, Leo will show completions whenever you type a period in the
body pane.
You can enable autocompletion in several ways:
1. By setting @bool enable_autocompleter_initially = True.
2. By using the toggle-autocompleter (Alt-1) command.
Displaying autocompletions
==========================
How Leo displays these completions depends on the setting::
@bool use_qcompleter
True: Leo shows completions in the QCompleter popup window.
False: Leo shows completions in the log pane.
Using the QCompleter
====================
When the ``@bool use_qcompleter`` setting is False, Leo shows all
completions in a
popup window, regardless of how many completions there are. To **accept** a
completion, use the up and down arrows to select a completion, then type the
return key. To **cancel** completion, type the escape key. As an important
shortcut, if the popup window contains only one entry, you may accept a
completion by simply typing the return key.
Using the Log pane completer
============================
When the ``@bool use_qcompleter`` setting is True, Leo shows completions in in
Leo's log pane. When there are more than 20 completions, Leo shows only the
characters that start a completions. For example, when completing ``os.path.``
the log pane will show::
_ 17
a 2
b 1
c 2
d 3
e 4
g 5
i 5
j 1
l 1
n 2
o 1
p 2
r 2
s 10
To see the complete list, type the '!' character. You will see::
__all__
__builtins__
__cached__
__doc__
__file__
__name__
__package__
_get_altsep
_get_bothseps
_get_colon
_get_dot
_get_empty
_get_sep
_get_special
_getfileinformation
_getfinalpathname
_getfullpathname
abspath
altsep
basename
commonprefix
curdir
defpath
devnull
dirname
exists
...
Typically, however, you would simply type one of the valid prefix characters.
For example, typing the letter 'a' would create the context ``os.path.a`` and
the log pane would show::
abspath
altsep
As you type, Leo enters the longest common prefix of all completions into the
body pane. Typing return, escape or ctrl-g (or any other alt or ctrl key) ends
completion.
Showing docstrings
==================
Regardless of the setting of ``@bool use_qcompleter``,
typing '?' during autocompletion will show the docstring of
the present context. For example, suppose the context is
``os.path.join``. Now typing '?' will show::
Join two or more pathname components, inserting "\" as needed.
If any component is an absolute path, all previous path components
will be discarded.
It is not possible to copy the docstring from the log pane
when using the QCompleter because the QCompleter popup window is a modal dialog.
Edward
I was confused by the instructions:
> python <<path to leo>>\leo\external\codewise.py %*
>
> A. [Optional] Create a custom ~/.ctags file containing default
> configuration settings for ctags::
>
> codewise setup
I was replacing the % with "codewise setup" ie:
$ python <<path to leo>>\leo\external\codewise.py codewise setup
then I wondered if there should be script in my path named "codewise"
then I figured out that "codewise" was an alias for <path>/codewise.py
I think it would be clearer to me if instead of
codewise setup
I just read
setup
I ran
$python codewise.py setup
$python codewise.py init
$python codewise.py parse my/lib/
$python codewise.py parse leo-editor/leo/core/
next: how to activate completion?
- loaded leoDocs.leo from help menu, did a "nav" on "completer"
- usage instructions were a few pages down
OK, press <ALT 1>, log pane tells me autocomplete is on.
Now it's becoming useful. A few observations.
If I want
leo.core.leoCommands.leoNodes.position
all is well if I type as above: each "." brings up the correct set of choices.
If I type
leoNodes.
I get a list which looks like every known token ...
**THIS JUST IN**
Another message from Edward ... signing off to study it ...
Thanks,
Kent
>
> Edward
>
> --
> You received this message because you are subscribed to the Google Groups "leo-editor" group.
> To post to this group, send email to leo-e...@googlegroups.com.
> To unsubscribe from this group, send email to leo-editor+...@googlegroups.com.
> For more options, visit this group at http://groups.google.com/group/leo-editor?hl=en.
>
>
> I was confused by the instructions:
>> python <<path to leo>>\leo\external\codewise.py %*
Yes. It's surprising how the "easy" stuff isn't.
Still, the main thing is to get python to execute leo/external
codewise.py with a single argument, which is either "setup", "init" or
"parse" (without the quotes :-)
> I was replacing the % with "codewise setup" ie:
%* means all arguments to the script, in this case codewise.bat.
Please translate to the Linux world...
Edward
I'll continue with more "careful" posts tomorrow, but now that I am
more familiar with the code and settings and what they do (or don't
do), I'd like to "jump ahead" with some ideas that Terry might use
immediately.
The main thing to know is that Leo's autocompleter *always* tries
Leo-specific completions, and then falls back to ctags/codewise
completions using Ville's codewise module to "make sense" of the
unified database ~/.codewise.db. Again, I'll leave the details of the
codewise magic for another post.
Indeed, ac.get_completions, leoPy.leo::
class AutoCompleterClass-->Helpers-->get_completions & helpers
computes the list of completions as follows::
aList = (
self.get_leo_completions(prefix) or
self.get_codewise_completions(prefix)
)
Again, notice the dog that isn't barking: no settings or other
switches are involved.
Let's look at get_leo_completions. In essence, it is just::
d = self.get_leo_namespace(prefix)
aList = self.attr_matches(prefix,d)
aList.sort()
Only ac.get_leo_namespace is of real interest. Here it is::
def get_leo_namespace (self,prefix):
'''Return an environment in which to evaluate prefix.
Add some common standard library modules as needed.'''
k = self.k
d = {'c':k.c, 'p':k.c.p, 'g':g}
aList = prefix.split('.')
if len(aList) > 1:
name = aList[0]
m = sys.modules.get(name)
if m: d[name]= m
return d
Ok, so here is my idea. The blender 'bpy' module is the "root" of all
blender scripting code. Suppose we add something like the following
code (untested) right after the definition of d::
if self.use_blender_completions:
<< add path to blender's python library to sys.path >>
import bpy
d['bpy'] = bpy
Now Leo should be able to recognize the 'bpy' module just like Leo
recognizes the 'c', 'g' and 'p' objects, and the various Python
modules that are added to the context.
Wouldn't this be an easy way to adding support for Blender autocompletions?
**Important**: very likely, one could do something almost as simple in
order to add Blender support using ctags/codewise. The choice might
be arbitrary, or it may turn out that the codewise way is a bit better
in general. However, patching get_leo_namespace can be done quickly
as a prototype.
We might want to generalize the hack to get_leo_namespace by adding
other useful symbols for Blender programming. Not exactly sure what
they are, but whatever they are it should be easy to support them.
Otoh, perhaps the generality of the ctags/codewise approach will make
further hacks moot.
Terry, what do you think?
Edward
I haven't had time to completely digest these posts yet, will try
ctagging blender when I can. But if leo can introspect bpy.* as
effectively as ipython does that kind of thing, or blender's own
autocompletion, then adding bpy as a namespace might be very effective,
I guess it's only a matter of "import bpy".
Of course, that would mean I'd have to use Leo with Python 3.x, which
would mean getting 3.x PyQt installed...
Cheers -Terry
> Of course, that would mean I'd have to use Leo with Python 3.x, which
> would mean getting 3.x PyQt installed...
Which might be a plus for the codewise approach, seeing I imagine you
can use a codewise database generated with Python 3.x from Leo-Qt-2.x.
Cheers -Terry
> Of course, that would mean I'd have to use Leo with Python 3.x, which
> would mean getting 3.x PyQt installed...
Why is that? Blender compiles with Python 2.6, iirc.
Edward
> > Of course, that would mean I'd have to use Leo with Python 3.x, which
> > would mean getting 3.x PyQt installed...
>
> Why is that? Blender compiles with Python 2.6, iirc.
Blender 2.5x requires Python 3.x, I'm fairly sure, not positive.
Cheers -Terry
> Now the door is unlocked. We can import sys in the same way, add
> paths to sys.path, and use the *embedded* imp module to load the 'bpy'
> module. If all goes as expected, the bpy should be able to import the
> '_bpy' module. Stay tuned...
Alas, not so. The problem is that Blender's init logic creates the
_bpy module, and to do that essentially all of Blender's init logic
must already have taken place.
The init logic consists of main() in creator.c, BPY_python_start() in
bpy_interface.py, and BPy_init_modules() in bpy.c. This is extremely
complicated code: it's out of the question to try to duplicate the
code from Python using ctags. Furthermore, even if we could run main()
from Python, it's not at clear that we could then access the *inited*
modules from the DLL's.
One could well imagine a Python bridge into Blender, but that bridge
must be created by *C* code. It is just barely possible that the
bridge already exists, but I haven't seen any evidence of it yet.
In short, it's unlikely that we can base the autocompletion on a
properly imported bpy module. We *can* still provide support for
Blender-oriented autocompletion in Leo, but it looks like we shall
have to use codewise to do it. Even this way may not be trivial--we
may have to use dummy description files to drive ctags.
Edward
> Furthermore, even if we could run main() from Python, it's not at clear that we could then access the *inited* modules from the DLL's.
This is a fascinating puzzle. Python's C API is tantalizing, but at
present I see no way to use it to create a proper Leo/Blender bridge.
Suppose we start blender *from Leo* by calling main(). Is there a way
to use a C API call to get access to the *properly inited* bpy (or
_bpy module)? I rather think not.
True, we can use the C API to run Python code using the embedded
Python interpreter, but that Python code will *not* run in the
environment created by main(!). In other words, the Python code
embedded in Blender does not, in fact, have access to the Blender's
data...
It's frustrating: it would be relatively simple to create (in C) a way
for *external* Python programs to gain access to the *properly inited*
Blender environment. The itsy-bitsy detail is that the C code doesn't
seem to exist.
However, it is just barely possible that there *do* exist one or more
access functions (or even variables) that would, say, allow access to
sys.modules *after* it has been inited by main() and its
helpers...I'll be looking for those bridges tomorrow.
Edward
> This is a fascinating puzzle. Python's C API is tantalizing, but at
> present I see no way to use it to create a proper Leo/Blender bridge.
Warning: this post is more geeky than I imagined for this thread.
Those not interested in gory details should skip it. I'll get back to
documenting autocompletion later, I promise. But not just yet, I'm
having too much fun :-)
Late last night I saw why this project is doomed, at least for the
moment. I had spent hours using an evaluation copy of PE Explorer,
http://www.heaventools.com/overview.htm, looking for all the C
functions I had found in the Blender sources. But I could not find
most of them in the export tables of blender.exe or python32.dll or
anywhere else.
Suddenly it occurred to me that just because a function was visible to
other C *functions* (the function wasn't static) did not mean that the
function had to be visible to other *DLLs*. Thus, most functions will
appear in *none* of the export tables in any of the DLLs. Doh!
Indeed, much of the code is "hidden" inside blender.exe. For example,
the main function is visible only as the entry point into blender.exe.
This means that most (all?) of the functions needed to init blender
simply will not be available via Python's ctypes module. End of
project. Still, it was a lot of fun looking at a major project from
the DLL point of view. And I learned more about calling sequences
than I ever dreamed there was too learn: See
http://en.wikipedia.org/wiki/X86_calling_conventions
All is not lost, however. As part of my explorations into the nooks
and crannies of the Blender *sources*, I found
blender/intern/bpy_introspect_ui.py. The comment at the head of the
file is::
# This script dumps ui definitions as XML.
# useful for finding bad api usage.
# Example usage:
# python intern/tools/bpy_introspect_ui.py
I haven't studied the code, but something like this, when run from
**inside** Blender (from the Blender console) could produce a
pure-python version of a "dummy" version of the bpy module and its
sub-modules bpy.data, bpy.ops, bpy.props, bpy.types, bpy.context,
bpy.utils. The same trick could be applied to the real (??) modules
bgl, blf, and mathutils.
After running the script, we simply make the dummy modules part of
Leo. We can then use *either* the eval-based approach or the
codewise-based approach to autocompletion.
This is good news. I've written lots of scripts like this. It can be
written inside Leo and imported into Blender by hand. It doesn't have
to be particularly easy to do the import: conceptually, the script
will only be run once. I'll start work on this project today...
Edward
P.S. But wait a minute! bpy_introspect_ui.py is to be run
**outside** of Blender!! What the heck is going on??
Hmm. There is a fake_main function that "creates" lots (all?) of
(fake?) instances of bpy.types, bpy.props, bpy.data, bpy.utils,
bpy.app and bpy.path.
Hahaha. After creating the fake bpy module, the script *imports* it.
It can then do some (fairly mysterious) manipulations that allow it to
create the xml file.
So the next step will be to run bpy_introspect_ui as a *Leo script*
with sys.path set up to appear to be run in
<blender-sources>/blender/intern. I can then study the script under a
microscope, clear up all its mysteries, and use it, maybe mostly
unchanged, to create the desired dummy Python modules. It looks like
a completely doable project.
EKR
> So the next step will be to run bpy_introspect_ui as a *Leo script*
Actually, bpy_introspect_ui.py appears to be a bit out of date. So
to reduce the amount of change, I am running it "in place".
I'm having great fun bringing it up to snuff as follows:
- The folder release/scripts/ui does not exist.
release/scripts/startup/bl_ui looks like a likely replacement.
- Added several new dummy classes so that the imports in
release/scripts/startup/bl_ui/*.py work
- Added several directories to sys.path
This is pretty much run-the-script-until-it-fails-then-hack-the-script approach.
Much like the conversion to Python 3k...
Oh yes, one more thing. Right next to the call to print(self.layout._as_xml())
there is a commented-out call to print(self.layout._as_python()).
Couldn't get much easier...
Edward
> Actually, bpy_introspect_ui.py appears to be a bit out of date. So
> to reduce the amount of change, I am running it "in place".
The modified script now runs to completion. Alas, it produces pretty
incomprehensible output.
Perhaps I can figure out how to make it do what I want, but that would
require actually understanding what it does ;-) I'll try now to
actually make sense of it using dumps of various kinds...
The alternative would be to run an introspection script from within
Blender itself. The script would use Python's inspect module to
gather all needed info about the modules we care about (the ones
mentioned when Blender's console starts up). The script would then
write dummy module definitions. Clearly, this script should be easier
to write than, say, jEdit2py...
Edward
> This has no chance of working--the script creates dummy classes which
> are of no value for autocompletion.
I've been trying to build blender from source, because I want to try
enabling an alternate library for 3d object intersection. I think as
part of that process it
creates .../blender-svn/blender/release/scripts/modules/bpy and friends
which might be good targets for codewise. They look like real python.
Haven't had a chance to test yet.
Cheers -Terry
> blender-svn/blender/release/scripts/modules/bpy and friends
> which might be good targets for codewise. They look like real python.
They are, but they are far from the whole story. For example,
bpy.types is missing.
Having said that, it's going to be "interesting" to get inspect to
tell us what we want. An initial attempt has revealed more problems
than solutions, but it is still early days...
Eventually, we are going to have to check what we get against the
docs, especially for bpy.types.x, of which there are very many:
http://www.blender.org/documentation/blender_python_api_2_59_2/bpy.types.html
Edward
> They are, but they are far from the whole story. For example,
> bpy.types is missing.
There is .../blender-svn/blender/release/scripts/modules/bpy_types.py
not sure if it's only created as part of the build process?
Cheers -Terry
> There is .../blender-svn/blender/release/scripts/modules/bpy_types.py
>
> not sure if it's only created as part of the build process?
A slightly different path prefix on windows, but I see it. Thanks. I
don't think I got far enough in the build process to generate the
file, so I think it came with the distro.
We are getting close. For sure ;-)
Jaworski's pypredef_gen.py mentions that it is based on Campbell
Barton's sphinx_doc_gen.py, which I gather is enough to generate all
the docs. On my machine, sphinx_doc_gen.py is in the sources distro
at blender/doc/python_api.
The files produced by pypredef_gen.py look like they are plenty good
enough for code completion. There is no .pypredef file for
bpy.context and bpy.types, but might just be because there is no
corresponding entries in the INCLUDE_MODULES list. Of course, these
modules could be special cases that pypredef_gen.py wouldn't be able
to handle, but surely sphinx_doc_gen.py *can* handle the special
cases, so in an emergency we could merge the two scripts.
I'm going to play around with pypredef_gen.py now. An obvious mod
would be to generate .py files (in some safe place) rather than
.pypredef files, and I'll see what happens when it tries to generate
bpy.context and bpy.types...
Edward