Skip to content
This repository has been archived by the owner on Dec 22, 2023. It is now read-only.

Can't do indent guide highlighting without brace matching #472

Closed
lafrank opened this issue Feb 28, 2020 · 4 comments
Closed

Can't do indent guide highlighting without brace matching #472

lafrank opened this issue Feb 28, 2020 · 4 comments

Comments

@lafrank
Copy link

lafrank commented Feb 28, 2020

For Python there should be no brace matching to perform indentation guide highlighting, but I caould not find a way to enable the latter when brace matching is disabled.

That is, the code below has no effect whatever column number is set for HighLighGuide:
scintilla.BraceHighlight(Scintilla.InvalidPosition, Scintilla.InvalidPosition); scintilla.HighlightGuide = caretPos;

@xv
Copy link

xv commented Feb 28, 2020

The property HighlightGuide is strictly tied to brace matching.

This is the code for HighLightGuide from Scintilla.cs:

public int HighlightGuide
{
    get
    {
        return DirectMessage(NativeMethods.SCI_GETHIGHLIGHTGUIDE).ToInt32();
    }
    set
    {
        value = Helpers.ClampMin(value, 0);
        DirectMessage(NativeMethods.SCI_SETHIGHLIGHTGUIDE, new IntPtr(value));
    }
}

Here's the documentation for SCI_GETHIGHLIGHTGUIDE & SCI_SETHIGHLIGHTGUIDE:

SCI_SETHIGHLIGHTGUIDE(position column)
SCI_GETHIGHLIGHTGUIDE → position
When brace highlighting occurs, the indentation guide corresponding to the braces may be highlighted with the brace highlighting style, STYLE_BRACELIGHT (34). Set column to 0 to cancel this highlight.

AFAIK, there's no built-in way to highlight guides without matching braces.

@lafrank
Copy link
Author

lafrank commented Feb 29, 2020

So how do I provide indent guide highlighting for Python ?

That would be extremely useful since Python is heavily depending on indentation but brace-matching has no added value here due to language syntax.
Just look at below example and imagine one has to find the right position for the next line :

image

Any idea how to resolve this ?
Thank you.

@xv
Copy link

xv commented Mar 1, 2020

Looking at SciTE's (Scintilla's demonstrator editor) way of highlighting Python indent guides, it seems based on a combination of two things:

  1. Having the caret placed on colons; and
  2. Having the lexer folding enabled.

The following method is a very rough translation of SciTE's code to highlight Python's indent guides:

static bool IsPythonColon(Scintilla sci, int pos)
{
    return sci.Lexer == Lexer.Python &&
           sci.GetStyleAt(pos) == sci.Styles[Style.Python.Operator].Index &&
           sci.GetCharAt(pos) == ':';
}

static void HighlightPyIndentGuide(Scintilla sci)
{
    var caretPos = sci.CurrentPosition;
    var braceAtCaret = -1;

    // Check if caret is before or after the colon and set pos
    if (caretPos > 0 && IsPythonColon(sci, caretPos - 1))
        braceAtCaret = caretPos - 1;
    else if (IsPythonColon(sci, caretPos))
        braceAtCaret = caretPos;

    // Colon exists
    if (braceAtCaret >= 0)
    {
        var lineStart = sci.LineFromPosition(braceAtCaret);
        var lineMaxSubord = sci.Lines[lineStart].GetLastChild(-1);
        var braceOpposite = sci.Lines[lineMaxSubord].EndPosition;

        var indentPos = sci.Lines[lineStart].IndentPosition;
        var indentPosNext = sci.Lines[lineStart + 1].IndentPosition;
        
        var columnAtCaret = sci.GetColumn(indentPos);
        var columnOpposite = sci.GetColumn(braceOpposite);

        // Don't highlight colon if at a parent-level indent (no guides)
        if (columnAtCaret != 0)
            sci.BraceHighlight(braceAtCaret, braceOpposite);

        var caretColumnNext = sci.GetColumn(indentPosNext);
        var indentSize = sci.IndentWidth;

        if ((caretColumnNext - indentSize) > 1)
            columnAtCaret = caretColumnNext - indentSize;

        if (columnOpposite == 0)
            columnOpposite = columnAtCaret;

        sci.HighlightGuide = Math.Min(columnAtCaret, columnOpposite);
    }
    else
    {
        sci.BraceHighlight(Scintilla.InvalidPosition, Scintilla.InvalidPosition);
        sci.HighlightGuide = 0;
    }
}

The method relies on lineMaxSubord to find the line where the indent guide ends, which in turn relies on the folding mechanism of the lexer to provide the correct folding levels. Therefore, you should only use it when folding is enabled, otherwise you'll observe incorrect highlighting behaviour.

You should carefully examine SciTE's code to learn form. This translation is buggy and it's merely just a push-start. It doesn't take into account colons that aren't used to start an indent suite, such as:

    # setting the caret on the colons would result in incorrectly
    # highlighting the indent guide
    dict = {
        'brand': "prada",
        'price': "treefiddy",
    }

@lafrank
Copy link
Author

lafrank commented Mar 1, 2020

Thank you xv, much appreciate your help with this !

@lafrank lafrank closed this as completed Mar 1, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants