hluk/FakeVim

Provide sip bindings to use FakeVim with PyQt

Closed this issue · 20 comments

More apps could take advantage of FakeVim if it had sip bindings to work with PyQt.

I'm not proficient enough at C or python to do this, but I would love to use FakeVim from within ReText (see https://sourceforge.net/p/retext/tickets/90/ ). I'm not even sure how to compile this since it doesn't have makefiles.

I looked at the sip docs but I'm not really sure which (or all?) header files need to be copied/converted into sip files. And I'm not quite sure which variables are private or protected.

The utils headers are short, but would anyone using FakeVim need access to them? or are they just for internal FakeVim use...? what about actions and handlers? It looks like there are 2 classes in actions and 1 class in handlers... but that doesn't really tell me anything useful (afaict).

Could you please create the sip files that are needed to run this through sip so that it can be used from python (with PyQt)? I'm hoping that once there are sip files, I (or someone) can figure out how to create the configure.py file.

hluk commented

Interesting, I'll take a look at that.

hluk commented

OK, that was illuminating :).

Check out: https://github.com/hluk/FakeVim/tree/master/python

Those are just quick bindings for PyQt. Few Qt signals are missing because I don't know how to expose some structs and enums.

FakeVim code is exact copy of the plugin from Qt Creator -- I want to keep it that way it's easier that way -- also Qt Creator has code reviews and lot of users. The downside is that there are now (could be easy to fix) additional names and headers from Qt Creator.

There is still lot of work to do to make the standalone version of FakeVim easy to use.

Behold the power of open source.

Thanks for working on this hluk! Hopefully this makes it's way into (a branch of?) ReText.

Thanks a lot for this!

It currently fails to build here with:

g++ -L../../build/fakevim -shared -o FakeVim.so sipFakeVimcmodule.o sipFakeVimFakeVimInternalFakeVimHandler.o sipFakeVimFakeVimInternal.o sipFakeVimFakeVim.o -L/usr/lib -L/usr/X11R6/lib -lfakevim -lQtCore -lQtGui
/usr/bin/ld: cannot find -lfakevim

Replacing -L../../build/fakevim with -L../../fakevim solves the problem for me.

Also, can you please support PyQt5 (as in ReText we have moved to PyQt5 in the latest release)?

hluk commented

I haven't tested it yet, but I think it should work with PyQt5 if you compile FakeVim with Qt 5 (using qmake for Qt 5 should be enough) and change "PyQt4" to "PyQt5" in configure.py and fakevimconfig.py.in.

The problem with the -L flag exists because there is currently no way to point the configure.py script to correct location where FakeVim was build. This path and Qt version should be configurable or detectable by the script.

Right now I'm just implementing new functionality and fixing the FakeVim library, but feel free to create pull requests or send me patches for the Python stuff.

I haven't tested it yet, but I think it should work with PyQt5 if you compile FakeVim with Qt 5 (using qmake for Qt 5 should be enough) and change "PyQt4" to "PyQt5" in configure.py and fakevimconfig.py.in.

It's not so simple because PyQt5 doesn't have pyqtconfig module. The only thing we can get is SIP flags:

from PyQt5.QtCore import PYQT_CONFIGURATION
pyqt_sip_flags = PYQT_CONFIGURATION['sip_flags']

For all other things, we should probably use sysconfig module. I don't have time to look at that now, so I've just commented here :)

I tried copying the qscintilla configure.py to see if that would get us any closer. They support both PyQt4 and PyQt5. See: https://github.com/cognifloyd/FakeVim/tree/python/qscintilla (once this is working, then it'll go in the python folder)

Testing with PyQt4 (I don't have PyQt5 installed):

  • your configure.py compiles, and the test runs.
  • the qscintilla configure.py also compiles, but the test fails on importing FakeVim.
    • it looks like it doesn't generate the fakevimconfig.py -- do we need that?

If you work with this, be sure to change the configure options in build.sh

hluk commented

The new configure.py file has over 1600 lines. This starts to be overly complicated.

For me this seems to work only with python 2.x and Qt 4 (with minor changes). With Qt 5, the script cannot find QtWidgets/QtWidgetsmod.sip. With python 3.4.1, the build library is incorrectly linked (doesn't link with /usr/lib/libpython3.4m.so).

There must be simpler way to do this, otherwise it would be hell to maintain.

Here's a sed script to create what I did from the QScintilla configure files:

# copy QScintilla's Python/configure*.py then:
sed -i \
    -e 's/QSCINTILLA/FAKEVIM/g' \
    -e 's/qscintilla2\?/fakevim/g' \
    -e 's/QScintilla2\?/FakeVim/g' \
    -e 's/QSCI/FAKEVIM/g' \
    -e 's/Qsci/FakeVim/g' \
    -e 's/qsci/fakevim/g' \
    -e 's/_API_MAJOR = 11/_API_MAJOR = 0/g' \
    -e "s/version *= *['\"].\..\..*['\"]/version=None/" \
    -e "s/minimum_sip_version *= *'.\...'/minimum_sip_version = '4.15'/" \
    -e "s/support@riverbankcomputing.com//" \
    -e "s/protected_is_public_is_supported = True/protected_is_public_is_supported = False/" \
    -e 's_sip/.*[345]\.sip_sip/fakevim.sip_' \
    configure*.py
sed -i \
    -e '/# Find .* header files/,/target_configuration.fakevim_version = fakevim_version/d' \
    configure.py
sed -i \
    -e '/# Find .* header files/,/sipconfig.error.*global\.h/d' \
    configure-old.py

All of the docs that I can find on how to build with PyQt5 treat QScintilla like a shining star. That's why I copied what they did. I started to expand your script, and I had all the pyqtconfig.* replaced except for the Makefile creation stuff.

Sadly, I reset/cleaned my git repo without realizing I hadn't committed those changes, so I would have to recreate it if it's needed. It shouldn't be as difficult if I have to do it again, but that doesn't solve the issue of: how do we replace pyqtconfig.QtGuiModuleMakefile?

So, how did you get the test to work with python2 and Qt4? ie What were the minor changes you made?

FYI: I sent a request for help to the PyQt mailing list: http://www.riverbankcomputing.com/pipermail/pyqt/2014-July/034547.html

@kovidgoyal suggested we can do something like what calibre's build system does:

hluk commented

So, how did you get the test to work with python2 and Qt4? ie What were the minor changes you made?

I needed to change the qmake executable. On my system qmake is symlinked to qmake-qt5. But the config script didn't set proper Qt version according to qmake -query. I had to add --qmake /usr/bin/qmake-qt4 parameters to the config script.

Also python executable is Python 3.4.1 for me so I need to use python2.

I'll check out the python scripts for Calibre. Thanks!

hluk commented

I've updated scripts to generate the bindings. Can you check it out? The commit is d16acac.

The default script variables should be sane enough for most people to run it -- right now it works fine on Arch Linux. It should be possible to build the bindings with any combination of Qt 4, Qt 5, Python 2.x and Python 3.x.

Awesome! That works well for me so far. Both compilation and testing works on my system:

  • Python 2.7.6
    • Qt 4.8.5
      • PyQt 4.10.3; Sip 4.15.3
      • PyQt 4.11.1; Sip 4.16.2
    • Qt 5.3.1
      • PyQt 5.3.1; Sip 4.16.2
  • Python 3.2.5
    • Qt 4.8.5
      • PyQt 4.10.3; Sip 4.15.3
      • PyQt 4.11.1; Sip 4.16.2
    • Qt 5.3.1
      • PyQt 5.3.1; Sip 4.16.2
  • Python 3.3.3
    • Qt 4.8.5
      • PyQt 4.10.3; Sip 4.15.3
      • PyQt 4.11.1; Sip 4.16.2
    • Qt 5.3.1
      • PyQt 5.3.1; Sip 4.16.2

This next setup does not compile for me because PyQt4 can only use one version of Qt at a time. I need to install another python interpreter to have a separate version of PyQt4 built against Qt5.

  • Python 2.7.6 & Python 3.2.5 & Python 3.3.3:
    • Qt 5.3.1; PyQt 4.11.1; Sip 4.16.2
      • sip: unable to find file "QtWidgets/QtWidgetsmod.sip"

When I had issues with a Segmentation fault, I had to fix these two issues:

  1. Qt5 wasn't really working anyway, so everything built with it segfaulted.
  2. FakeVim itself, not just the python bindings, needs to be built with the Qt5 qmake. (doh!)

To run these tests I had to set the PyQt include path to gentoo's non-standard location for PyQt4. Thanks to your clean build script, that wasn't a problem 👍 Thanks!

PYQT_INCLUDE_PATH=/usr/share/sip PYTHON=`which python2` python/build.sh

EDIT: I've been updating this comment as I've got more tests to run

hluk commented

Great. I guess there will be some issues when trying to use the scripts on OS X and Windows (or other compilers), but someone else will have to test that.

This line:

pythonLibrary = sysconfig.get_config_var('LIBDIR') + "/" + sysconfig.get_config_var('LDLIBRARY'),

does not work on Debian/Ubuntu, where LIBDIR is /usr/lib/, however Python libraries are in /usr/lib/ARCH-OS-TRIPLET (i.e. /usr/lib/x86_64-linux-gnu). I think you should insert sysconfig.get_config_var('MULTIARCH') in the middle, if that is available.

hluk commented

Thanks, fixed: 9a5592b (tested on Ubuntu 14.04)

hluk commented

I'm closing this. Open new issue if there are some problems.

I'm trying to improve FakeVim Python text (test.py) to see if it's possible to fully use FakeVim.

hluk commented

I've improved the test.py script. It opens simple text editor which supports among others:

  • block selections,
  • highlight search,
  • source .vimrc,
  • opening and saving files,
  • common editing commands.

Patches are welcome.