​​On Thu, Feb 4, 2016 at 10:25 AM, john lunzer <[email protected]> wrote:

> From here
> <http://stackoverflow.com/questions/26505729/how-to-display-non-printable-symbols-in-qtextedit-pyqt4>
>  I
> found a little snippet of code which makes tabs and spaces visible:
>
> doc = QtGui.QTextDocument()
> ​​
> option = QtGui.QTextOption()
> option.setFlags(QtGui.QTextOption.ShowTabsAndSpaces)
> ​​
> doc.setDefaultTextOption(option)
> textEdit = QtGui.QTextEdit()
> textEdit.setDocument(doc)
>
> From a different post
> <http://stackoverflow.com/questions/32147592/color-whitespace-and-paragraph-separators-in-qtextedit-with-qsyntaxhighlighter>
>  (although
> it is a C++ example) it shows that a custom highlighter can be used to
> colorize these visible tabs and spaces.
>

​Thanks for this!  It would be a good addition.​


>
> I have for a while wanted to make this change because the way Leo
> currently handles "invisibles" is too conspicuous to keep on all the time.
>
> I'm looking for some direction on how this might be integrated into Leo?
> Any help would be greatly appreciated.
>

​In general, the best approach is use the search command.  Nowadays, I
would use cff.  ​

​Let's try​ a search on setDocument...I get the following headlines:

    ctor (LeoQtSyntaxHighlighter)
    pqsh.setDocument
    pqsh.Birth & death

These are out of context, so let's use Alt-N (goto-next-clone) to find the
context. They are all in leoColorizer.py, which is a good sign.  The
python_qsh switch is True at the top of leoColorizer.py, which means that
the PythonQSyntaxHighlighter class is in effect.

Looking at pqsh.setDocument, it's clear that it is one place to apply the
patch. Indeed, there is this assert:

    assert isinstance(d, QtGui.QTextDocument), d

So let's apply the patch!  Right after the above assert:

    assert isinstance(d, QtGui.QTextDocument), d
    if d:
        if 1: # Show invisibles
            option = QtGui.QTextOption()
            option.setFlags(QtGui.QTextOption.ShowTabsAndSpaces)
            d.setDefaultTextOption(option)
        d.contentsChange.connect(self.q_reformatBlocks)
        d.rehighlightPending = True
            # Set d's pending flag.
        QtCore.QTimer.singleShot(0, self.delayedRehighlight)

And it works! So let's connect it for real.

Again, the only effective way is to start with a search.  Let's guess
showInvisibles, because there is a show-invisibles command. Heh, the first
hit is:

    self.showInvisibles = c.config.getBool("show_invisibles_by_default")

in the leoColorizer.py.

Now it gets really tricky. showInvisibles is an ivar of the JEditColorizer
class, but the code we are adding is in the PythonQSyntaxHighlighter class.
Actually, it's in the LeoQtSyntaxHighlighter class, a subclass of pqsh.

The ctor for LeoQtSyntaxHighlighter creates this ivar:

    self.colorer = JEditColorizer(...)

So the test we want in pqsh.setDocument is:

    if self.colorer.showInvisibles:

Let's try it.  Still throws an AttributeError, but we are close. The
problem is that LeoQtSyntaxHighlighter creates the pqsh class *before*
creating the colorer ivar.  So the solution is to create the pqsh class
*last*.  Yup, that works, or at least doesn't crash on startup :-)

But the toggle-invisibles command still doesn't work. Searching for
'toggle-invisibles' gets us to c.showInvisiblesHelper.  Hmm. It sets
colorizer.showInvisibles, not colorer.showInvisibles.

So let's add this line to c.showInvisiblesHelper:

    colorizer.highlighter.showInvisibles = val

Traces show that this is the correct ivar, but doh, pqsh.setDocument is
called only during startup. So it looks like we are going to have to
dynamically set the flags in pqsh.rehighlight_helper.  A trace confirms
that this helper is called when we do a toggle-invisibles.  Let's add this
code:

    if self.colorer.showInvisibles:
            option = QtGui.QTextOption()
            option.setFlags(QtGui.QTextOption.ShowTabsAndSpaces)
            self.d.setDefaultTextOption(option)

That works, but there are two problems.  First, the *old* way of showing
invisibles is still in effect, and second, there is no way to turn off the
new way of showing invisibles.

To handle the second problem, let's add an else clause.  Like this:

        option = QtGui.QTextOption()
        if self.colorer.showInvisibles:
            option.setFlags(QtGui.QTextOption.ShowTabsAndSpaces)
        self.d.setDefaultTextOption(option)

And that works.  But we still have to turn off the old way of highlighting
invisibles. Let's try commenting out a line in c. showInvisiblesHelper:

    # colorizer.showInvisibles = val

Nope.  That doesn't work.  Searching on showInvisibles gets us to:

   JEditColorizer.configure_variable_tags.

So what we want is to disable the code there, or to disable
JEditColorizer.showInvisibles.  Let's try the latter.

There is a comment that JEditColorizer is
c.frame.body.colorizer.highlighter.colorer

So let's *add* the following line to c.showInvisiblesHelper:

   colorizer.highlighter.colorer.showInvisibles = val

Still no joy.  Ah.  JEditColorizer.configure_variable_tags is only called
at startup. Looking further, we see that JEditColorizer.match_blanks tests
showInvisibles.  So let's just have it always return.

Yup.  That works.

I haven't upped this change. I suppose it could be yet another option, but
I think we should use the new code. It is the recommended Qt way. I plan to
do this soon, unless there are objections.

A long answer to your question.  The short answer is, use cff to find the
code to look at, and then play around and see what happens.

Edward

-- 
You received this message because you are subscribed to the Google Groups 
"leo-editor" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To post to this group, send email to [email protected].
Visit this group at https://groups.google.com/group/leo-editor.
For more options, visit https://groups.google.com/d/optout.

Reply via email to