Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature request: better bar layout for sexp-based modes #89

Open
jreicher opened this issue Nov 19, 2024 · 9 comments
Open

Feature request: better bar layout for sexp-based modes #89

jreicher opened this issue Nov 19, 2024 · 9 comments
Labels
help wanted Extra attention is needed

Comments

@jreicher
Copy link

I don't know if this is possible, but it might be good to inhibit bars if it is not the case that both ends of the bar meet either the start of some text or point. Although this will mean the bars won't show all scope depths, it is possible some users will only want them for visualising text alignment.

@jdtsmith
Copy link
Owner

Can you describe this idea visually? Not sure I get your meaning. You're aware you don't need to add bars to blank lines?

@jreicher
Copy link
Author

jreicher commented Nov 20, 2024

In something like the below

image

I would suggest only the bar from y to z is showing alignment of text. The other three bars aren't needed to show any alignment.

@jdtsmith
Copy link
Owner

jdtsmith commented Nov 20, 2024

The simple answer is that indent-bars shows alignment only by side-effect; what it actually shows is the indentation depth in fixed increments. For languages like elisp where indentation only barely respects a fixed width grid (unlike say Python or YAML), indent-bars is less useful, I agree.

The display capability of fading out e.g. the 1st two bars exists (as you can see in the screencast for TS modes). But what sort of general purpose, works-everywhere algorithm would you propose? Here's what indent-bars knows about a given line:

  • If the line is blank or not.
  • How many "indentation steps" there are on the line.
  • What is the position (and indent level) of the containing list context (parens).

@jreicher
Copy link
Author

I think this idea is essentially a different kind of information for the third point. Instead of the position and indent level of the containing list context, I think a kind of generic indentation context is needed about each line that looks something like this:

A list of columns where all of the "most recent" indented lines started. And by "most recent" I mean that in something like

   aaa
bbb
   ccc
      ddd

at line "ddd" only the indentation for "ccc" is known. The line "bbb" hides the line "aaa".

And then the other piece of information is another list of columns essentially the same, but reading the buffer in reverse.

Then a bar is drawn at every column that appears in both lists.

It should be possible to construct these lists in one pass of the buffer each. For the one going forward I think the algorithm would be

  1. Use the current line's "indents above" list as the initial working list for the next line (for the first line this is nil)
  2. Remove all columns from the list that are greater than or equal to the starting column of the current line
  3. Add to the list the starting column of the current line

The resulting list should be the "indents above" list for the next line (and also the initial working list for the line after that).

Construct an "indents below" list the same way, reading the buffer in reverse.

I'm fairly sure this would render a read-only buffer just fine, but I'm not sure how efficient it would to update a buffer being edited.

@jdtsmith
Copy link
Owner

list of columns where all of the "most recent" indented lines ... should be possible to construct these lists in one pass of the buffer each

That's far too heavy.

There is no possible "pass of the buffer" other than treesit context. You cannot use all indents above, only current and adjacent lines, otherwise random edits would require re-parsing much of the buffer on every keystroke. You can think if there's an algorithm with the mentioned ingredients.

@jreicher
Copy link
Author

Yes I thought you might say that.

I can try to come up with a dynamic algorithm, but no matter how efficient it is editing one line might still result in removing or adding a bar on an unknown number of other lines, and at worst case the entire buffer.

Is this kind of potential redraw feasible? If not there's no point figuring out a dynamic algorithm.

Thanks.

@jdtsmith
Copy link
Owner

It's very possible. font/jit-lock do allow you to expand region and redraw potentially large sections of the buffer. There is already precedent: in TS modes, moving point actually causes large sections of the buffer to be invalidated and redrawn (with a special speed-up of avoiding normal font lock on regions where only bars have changed).

For your case, it might be possible, for example, to invalidate an entire sexp region, but for each line's illuminated bar set to be calculable locally, based on list context. You could imagine doing this with containing TS context too, but that's more complex.

To start, why don't you mock up a suite of examples and develop a rough "explanatory" algorithm that you think would be an improvement, looking for counter examples and corner cases. I'm not convinced such an algorithm exists which is robust for some/all non-grid-adhering, sexp-based indentation schemes.

@jdtsmith jdtsmith added the help wanted Extra attention is needed label Dec 20, 2024
@jdtsmith jdtsmith changed the title Feature request: inhibit bars that do not align with the start of some text Feature request: better bar layout for sexp-based modes Dec 20, 2024
@jdtsmith
Copy link
Owner

Leaving this open in case anyone wants to work on a simple local algorithm that can improve the indent positions for sexp-type modes that do not for the most part respect a fixed indentation grid.

@jdtsmith
Copy link
Owner

One thing that could be played with is, for a given line, the indentation level of all of the containing SEXP starts (i.e. all the enclosing (). Since many of these will be on the same line (and can hence be ignored), this is likely a tractable expense. So we could try adding that to the list of "things indent-bars can know about a given line`:

  1. Whether the line is blank
  2. Local indentation depth (perhaps as a special case, in char spaces, not steps, since sexp modes so often ignore indentation steps).
  3. Similar indentation depth of the starts of all containing sexps.

I worry about the stability of an algorithm that changes long ranges of bars based on a single space being added or removed. But it's certainly possible to think about. For anyone who wants to look into this, I'd suggest grabbing a reasonable chunk of code in an sexp-based language (like Elisp), and mocking up "bars you'd want brightly visible", then we can see how it might map to the above list of "ingredients" in terms of an algorithm.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
help wanted Extra attention is needed
Projects
None yet
Development

No branches or pull requests

2 participants