jdtsmith / indent-bars

Fast, configurable indentation guide-bars for Emacs
GNU General Public License v3.0
272 stars 7 forks source link

is it possible to emphasis the in-scope indent bars instead of de-emphasizing the out-scope bars #45

Closed oxcl closed 1 month ago

oxcl commented 1 month ago

thank you for the amazing package. is there a way to set a different color for the indent bars inside the scope instead of using the *-ts-* variables to change the out of scope indent bars?

jdtsmith commented 1 month ago

Glad to hear scope styling is working for you. Can you let me know what mode?

Yes, you can fully configure all the colors and styles in-scope and out-of-scope. Even whether the current depth is highlighted.

However you configure for all the normal (non-ts) variables will provide the in-scope styling, and the *-ts-* variables will then provide the out-of-scope style. They don't need to be related at all, the mention of "de-emphasizing" is just to make it easy to visualize one choice you might make. There is the concept of the out-of-scope vars "inheriting" from the in-scope, but that's not required. Just treat them as a parallel set of custom vars and have fun. M-x customize-group indent-bars and look at the end for in-scope and out-of-scope style menus.

I need to get together some examples, so if you come up with something good, post it.

oxcl commented 1 month ago

Well i have only tested the scope highlighting briefly with bash-ts-mode but it seems like it's working without any issues.

So what i want to achieve is that i want to have a default color for all indent lines across buffers that might or might not have treesitter. But in the buffers that have treesitter support i want the in-scope indent lines to be slightly brighter and the outscope indent lines to stay the same. Please correct me if I'm wrong but i think that's not currently possible. I have read the Readme and couldn't figure out how to do it.

jdtsmith commented 1 month ago

I see, hadn't thought of that possibility. I don't think there's a great way to do this at present, since the faces are global and used across all buffers with bars. There is no technical reason we couldn't invert the mapping of what the -ts- vars specify (i.e. is in-scope default, or out-of-scope?).

You can see that for people who want the opposite effect, it would be problematic if the out-of-scope faces mapped to the non-ts-mode bars: everything in those modes would be "de-emphasized"! Let me think if there's a convenient way to "invert the correspondence" by a setting.

jdtsmith commented 1 month ago

OK, I have added an option indent-bars-ts-styling-scope, by which you can interchange the role of the *-ts-* variables to apply to the in-scope bars, and out-of-scope bars to share the default styling. Please check out the dev branch and give this a test and report. This branch also has a simplified method for drawing in-scope bars. Let me know of any issues.

oxcl commented 1 month ago

thanks! it seems like there is a problem with the way in-scope lines are highlighted 2024-05-29-08-58-12 this is my config:

  (use-package indent-bars
    :ensure (:host github :repo "jdtsmith/indent-bars" :branch "dev")
    :config
    (setq indent-bars-color '("yellow" :blend 0.15)
          indent-bars-ts-color '("red" :blend 0.5)
          indent-bars-color-by-depth nil
          indent-bars-pattern "."
          indent-bars-width-frac 0.1
          indent-bars-no-descend-string t
          indent-bars-treesit-support t
          indent-bars-treesit-update-delay 0.1
          indent-bars-treesit-scope '((bash if_statement do_group subshell test_command compound_statement else_clause case_statement case_item))
          indent-bars-ts-styling-scope 'in-scope
          indent-bars-treesit-scope-min-lines 2)
    :hook (prog-mode conf-mode)
    :hook (emacs-lisp-mode . (lambda () (indent-bars-mode -1))))

things i notice is that when cursor is on a line not only the in-scope indent-bars of that scope get selected but the in-scope indent-bars of it's children also get selected as well. i don't know if that is the intended behavior or not so for a code like this:

if 1; then
   if 1; then
        echo "code inside the child if"
   fi
   echo "code inside the parent if"
fi

when the cursor is on the echo command for the parrent if block, the indent bars for the child block also get highlighted. in my opinion i think only the indent bars for the parent if statement should be highlighted there also seems to be another issue with neighbouring scopes being selected when hovering over the if statements themselves. but i don't really understand it enough to describe it. it is illustrated in the gif image

jdtsmith commented 1 month ago

There are two forms of highlighting: scope, and current depth bar. You haven't made clear which you are referring to, and your GIF doesn't make it clear what the problem is (they rarely do). Just guessing here, but it seems to me like one of your listed TS capture node types is very localized, capturing individual *) cases within case, for example. I don't know bash TS, but you can M-x treesit-explore-mode to find out which one it is. As recommended in the docs, you should remove all the node types and add them slowly one by one to make sure you need them (M-x indent-bars-reset in between).

when the cursor is on the echo command for the parrent if block, the indent bars for the child block also get highlighted

This isn't clear. Show me this with an [X] on your code? If you mean the final echo statement above, point on that line will presumably be found within the outer if statement as the scope. So you'd expect two bars to get "in-scope" highlighting, like so:

if 1; then
|   if 1; then
|   |     echo "code inside the child if"
|   fi
|   [X] echo "code inside the parent if"
fi

Scope obviously refers to everything within the current scope. For example, if the innermost scope at point is the body of a function, all the bars within that function at any depth will be in scope, and get special *-ts-* styling.

Separately, if you have current depth highlighting enabled (see indent-bars-highlight-current-depth), the "current bar" at a single depth will receive current depth highlighting. All the bars outside that function (above, below, or left of) will have the other style (de-emphasized, for me).

Also there are a few styles for which bar is selected as the "current depth". Did you read the docs regarding Current Depth Highlight? I'm just guessing here, but I'd suspect you have added too many things to indent-bars-treesit-scope. Also, can you do this in GUI emacs? Styling is much clearer there.

oxcl commented 1 month ago

There are two forms of highlighting: scope, and current depth bar. You haven't made clear which you are referring to, and your GIF doesn't make it clear what the problem is (they rarely do).

sorry if I wasn't able to articulate my problem correctly. I have played around this a bit more and i think there are two issues here. i tried to compare the behavior of this package with VSCode which is the behavior i'm trying to achieve. I highlighted the highlighted scope with red and others with yellow (couldn't figure out how to do it in VSCode, as well. sorry if it's not clear enough)

the first issue is that when hovering the cursor over the beginning of an scope instead of that scope being highlighted the parent scope gets highlighted. for this code:

function test_function(){
    if(5 > 10){
        console.log("neighboring scope")
    }
    if(5 > 10){
        console.log("inner scope")
    }
    console.log("outer scope")
}

vscode does this: Screenshot 2024-05-29 162815 while indent-bars does this: Screenshot 2024-05-29 162150 I have noticed that this happens only when the cursor is on the beginning of the if statement vscode: Screenshot 2024-05-29 161644 indent-bars: Screenshot 2024-05-29 162218

I'm not sure if this is the intended behavior of the package or not. I think what is happening is that VSCode determines the scope of the block only by the line number. so even if the cursor is on the beginning of the if statement (or even before that in the indentation space) the highlighted scope will stay the same.

oxcl commented 1 month ago

and for the second issue that i'm facing what i'm trying to achive is probably a combination of both current depth highlighting and scope highlighting.

Scope obviously refers to everything within the current scope. For example, if the innermost scope at point is the body of a function, all the bars within that function at any depth will be in scope, and get special -ts- styling.

i want the current depth to be highlighted but only for the current scope. the desired behavior would be highlighting the current scope with the current depth of where the cursor is sitting but excluding the child scopes that have a higher depth. (similar to how vscode works)

vscode: Screenshot 2024-05-29 161605

indent-bars: Screenshot 2024-05-29 162239

I hope i was able to illustrate the problem without overexplaining. thanks for your time.

my config (setq indent-bars-color '("yellow" :blend 1) indent-bars-ts-color '("red" :blend 1) indent-bars-color-by-depth nil indent-bars-pattern "." indent-bars-width-frac 0.1 indent-bars-no-descend-string t indent-bars-treesit-support t indent-bars-treesit-update-delay 0.1 indent-bars-starting-column 0 indent-bars-treesit-scope '((typescript if_statement statement_block)) ; '((bash if_statement do_group subshell test_command compound_statement else_clause case_statement case_item)) indent-bars-ts-styling-scope 'in-scope indent-bars-treesit-scope-min-lines 1)
jdtsmith commented 1 month ago

i want the current depth to be highlighted but only for the current scope

Then deactivate current depth highlight for the out of scope style!

when hovering the cursor over the beginning of an scope instead of that scope being highlighted the parent scope gets highlighted.

Different people disagree on the correct way to select the "current depth" at point (e.g. #36). So there is a setting. Maybe you missed this from my earlier message:

Also there are a few styles for which bar is selected as the "current depth". Did you read the docs regarding Current Depth Highlight?

You are still confusing and conflating two independent forms of highlighting: scope and current depth. They are separate. Suggestion:

  1. Turn current depth highlighting fully off to start. (indent-bars-highlight-current-depth=nil)
  2. Tune the scope mode types until you are happy with scope highlight (start with a short list).
  3. Once scope is to your liking, turn current depth highlighting on, but keep off for the out of scope vars.
  4. Play with current depth style (3 options) until it works like you want.
jdtsmith commented 1 month ago

Also, in your vscode it looks like all bars are the same. Please no more screenshots. Instead, in source blocks, use the following markers:

And show me on a small but non-trivial piece of code what you currently get, and what you want. Here's an example with the default settings and a block of Python:


    if flag:
    :   while True:
    :   ;   spin()
    :   ;   
    while True:
    :   line = input()        
    :   if [X]line.startswith(">>_ipb_>>"):
    :   !   if cell:
    :   !   |   get_ipython().run_cell(cell)
    :   !   |   cell = ""
    :   !   if line.endswith("DONE"):
    :   !   |   print("<<_ipb_<<BYE")
    :   !   |   break
    :   !   elif line.endswith("NEXT"):
    :   !   |   print("<<_ipb_<<GO")
    :   else:
    :   !   cell += "\n" + line
oxcl commented 1 month ago

Then deactivate current depth highlight for the out of scope style!

ok i see, basically i was thinking about it the opposite way. if I'm not mistaken instead of first selecting the current scope and highlighting the current depth, the actual approach is to select current depth and exclude the out of scope bars.

I think i can figure it out now. thnaks for your help

jdtsmith commented 1 month ago

the actual approach is to select current depth and exclude the out of scope bars.

Gah! As I keep mentioning, they are INDEPENDENT! Scope gets selected quite precisely: treesitter is queried for the innermost node you specified in treesit-scope which contains point. This is "the scope". At the beginning position of "the scope", the number of showing bars there are considered "out of scope", and all deeper bars are "in scope" (only within the scope region). Everything outside "the scope" is naturally "out of scope".

Depth is selected based on the line point is on only, no treesitter involved; see `indent-bars-highlight-selection-method' for the methods by which it is selected.

If you do get something working that approximates vscode, please post it here and I'll add to the examples. BTW since you are on terminal you could use a thin vertical bar for normal and heavy bar for one of the highlights (scope or current depth: which again, are completely independent :)).

oxcl commented 1 month ago

Gah! As I keep mentioning, they are INDEPENDENT! Scope gets selected quite precisely: treesitter is queried for the innermost node you specified in treesit-scope which contains point. This is "the scope". At the beginning position of "the scope", the number of showing bars there are considered "out of scope", and all deeper bars are "in scope" (only within the scope region). Everything outside "the scope" is naturally "out of scope".

sorry if I'm bothering you. I just started learning about emacs just recently and not a pro user

I understand the fact that they are independent of each other what i meant to say was that if I set indent-bars-ts-color and 'indent-bars-color' to the same color and use a different color for indent-bars-highlight-current-depth it should have the same effect as highlighting the current depth but only for the current scope

basically I'm hoping for the indent-bars-ts-color highlighting to override the indent-bars-highlight-current-depth highlighting so that it will look the same as the normal indent bars

am I wrong in my assesment?

currently I'm trying to do this with this config:

(setq indent-bars-color '("red" :blend 1)
         indent-bars-ts-color '("red" :blend 1)
         indent-bars-highlight-current-depth '(:color "green" :blend 1)
         indent-bars-starting-column 0
         indent-bars-color-by-depth nil
         indent-bars-treesit-support t
         indent-bars-pattern ". . . ."
         indent-bars-treesit-scope '((bash if_statement))
         indent-bars-treesit-scope-min-lines 0)

but there seems to be a problem with the current-depth styling taking precedence over the out of scope one. so for a code like this:


if 0; then
:   print "text inside the parent block"
:   if 1; then
:   |    print "text inside the child2 block"
:   fi

:   if 2; then
:   !   # child 2
:   !   [X]print "text inside the child1 block"
:   fi
fi

so the current depth for the child 2 gets highlighted green which is what i want. but the bar for child 1 also gets highlighted to green. even though it is out-of-scope and should be colored red

If you do get something working that approximates vscode, please post it here and I'll add to the examples. BTW since you are on terminal you could use a thin vertical bar for normal and heavy bar for one of the highlights (scope or current depth: which again, are completely independent :)).

sure i will definitely share the code if i get it to work I actually use the GUI but i use the terminal for recording gifs with asciinema which is easier than recording the screen.

jdtsmith commented 1 month ago

It's OK, it's a pretty complicated (if powerful) config system. Current depth styling always "wins", and what you may not understand: it applies everywhere. Every bar at the current highlight depth is highlighted, everywhere in the file. If you don't have TS, that's the end of the story. It uses face-remapping in fact to do this very quickly (depth 4 bar face => depth 4 highlighted bar face).

But here's the key: with TS, there are two active current depth styles: in-scope and out-of-scope (either or both can be disabled). By default the ts version (which is maybe in-scope, for you, though not in the above settings?) inherits the settings of the non-ts "default" versions. So in your case, both out-of-scope and in-scope highlight bars are fully "green" (blend=1 ensures that, i.e. no blend with the underlying color). Including a different :pattern, :zigzag, etc. would show the difference. As would having :blend<1 and using different normal colors in-scope and out-of-scope.

So here I think what you have written as | is actually a ;, i.e. an out of scope, current depth highlighted bar. Because you have both depth highlight styles set to the same thing you can't tell the difference. Do you really want no differences between in-scope and out-of-scope style? If so, i.e. you are using the same style overall for both, you don't actually need the new setting to switch in/out-of-scope (which I see anyway you don't have set above).

Options:

No out of scope highlighting:

indent-bars-color '("red" :blend 1) ; put red bars
indent-bars-ts-color '(unspecified) ; inherit indent-bars-color for out-of-scope
indent-bars-highlight-current-depth = '(:color "green") ; in scope: green highlight bars
indent-bars-ts-highlight-current-depth = nil ; out of scope: no highlight bars

(Note that indent-bars-reset is sometimes not enough when changing these during a session; you might need to (setq face-remapping-alist nil). Update: I think I just fixed that in dev.)

Alternative pattern out of scope:

indent-bars-ts-pattern = ".   "

Plus a million more options in which you set in and out of scope bars to look different (blend, color, pattern, zigzag, etc.).

jdtsmith commented 1 month ago

it should have the same effect as highlighting the current depth but only for the current scope

I.e. that would be true, except by default -ts- variables inherit from their non--ts- parent.

jdtsmith commented 1 month ago

BTW have you tried the customize interface? For non-pro users I think it's WAY easier. Take a look.

oxcl commented 1 month ago

so assume a config like this:

     indent-bars-color '("red" :blend 1) 
     indent-bars-ts-color '("white" :blend 1) 
     indent-bars-highlight-current-depth '(:color "green") 

if we assume . is white | is green : is red

i would expect something like this:

#!/usr/bin/env bash

if 0; then
.    print "text inside the parent block"
.    if 1; then
.    .    print "text inside the child2 block"
.    fi
.
.    if 2; then
.    |    # child 2
.    |    [X]print "text inside the child1 block"
.    fi
fi

if 0; then
.    print "the rest"
fi

but what i'm actually getting right now is:

if 0; then
.    print "text inside the parent block"
.    if 1; then
.    |    # child 1
.    |    print "text inside the child2 block"
.    fi
.
.    if 2; then
.    |    # child 2
.    |    [X]print "text inside the child2 block"
.    fi
fi

if 0; then
.    print "the rest"
fi
a screenshot ![image](https://github.com/jdtsmith/indent-bars/assets/109025334/6f37728e-b714-45e2-8231-41c8d4c2804c)

what I'm trying to achieve is to override the green bar of the child1 to be a white line since it's out of scope but it seems like that the highlighting for current depth takes precedence over the -ts- highlighting.

P.S: indent-bars-ts-styling-scope is set to default out-of-scope

jdtsmith commented 1 month ago

No, you are highlighting the in-scope and out-of-scope current-depth bars the exact same way with this setup. Did you forget indent-bars-ts-highlight-current-depth = nil? That is key, because, as mentioned, otherwise highlight-current-depth inherits the same style — (:color "green").

For the default setup, having current-depth inherit is fine, because it changes something orthogonal from the in/out-of-scope distinction (bar pattern). But you have no such distinction, and are just changing color, so you need to disable depth highlighting out of the scope region.

I really think the Custom interface would serve you much better, please give it a try. I've just pushed some changes to dev so you can see a live immediate update when you make changes there. Just open a buffer of interest with bars alongside the Customize group for indent-bars[,-style,-ts,-ts-style] and make some changes, apply (C-c C-c is nice), and see how you did.

oxcl commented 1 month ago

No, you are highlighting the in-scope and out-of-scope current-depth bars the exact same way with this setup. Did you forget indent-bars-ts-highlight-current-depth = nil?

yep. indent-bars-ts-highlight-current-depth = nil was the missing part. even though you mentioned it. it totally went over my head.

finally got it to work properly using this setup:

    (setq indent-bars-color '("white" :blend 0.1)
          indent-bars-highlight-current-depth '(:color "white" :blend 0.25)
          indent-bars-ts-highlight-current-depth nil
          indent-bars-starting-column 0
          indent-bars-color-by-depth nil
          indent-bars-pattern "."
          indent-bars-width-frac 0.1
          indent-bars-treesit-support t
          indent-bars-treesit-scope '((bash if_statement))
          indent-bars-depth-update-delay 0.03
          indent-bars-treesit-update-delay 0.1
          indent-bars-treesit-scope-min-lines 0)

thank you for baring with me through this long journey!