Skip to content

Conversation

@pysan3
Copy link
Collaborator

@pysan3 pysan3 commented Oct 24, 2022

Hi, I love the extensibility of this plugin.

I think this feature (#547) is quite useful, especially when you want to peek a filename or dealing with very deep file structures.

I tried to implement this feature with the following configs and I would like to hear your opinions.

What I did

1. Added option window.auto_expand_width

Default: false

Usually, long file names and deep hierarchy folders (by the indents) are truncated and goes underneath modified symbols etc. However, by setting this to true, the filename is not truncated and instead, the window width is expanded (ignoring window.width option) to show the whole content.

Default window.auto_expand_width = true
image image

What it differs from width = "fit_content" is that the window width expands even after launching neotree, meaning that when a new folder with a very longfile name is expanded, neotree window adjusts its width to fit the new filename.

2022-10-24 18-04-27

2. Added command toggle_auto_expand_width (with keybind)

Although I added the above feature, I actually like the fading effect on normal circumstances.
So I created a keybind that toggles window.auto_expand_width.

In my usecase (and IMO recommended to everybody) is to keep window.auto_expand_width option to false and toggle the feature whenever needed.

Currently it is binded to e. In the gif bellow, I am pressing e several times after opening neotree.

2022-10-24 18-04-53

Know Issues

There are some issues with the current implementation. However, I don't think this is a big problem because, first of all, not so many people are going to use (or even notice) this feature, and second, it hardly effects the usability.

  • Window width of the lines above the very-long-file-name.txt is not updated
    • This is pretty much impossible to fix because the length of lines are calculated on the fly.
    • Not a big problem since it will get fixed by renderer.redraw(state), i.e. doing any of the followings
      • reopen neotree
      • open another directory or make a new file or do something that will fire an update
  • The default keybind e conflicts with example.window.example_command?
    • I have never used this keybind and have no idea what it is for.
    • I would like to hear @cseickel and others' ideas about a better keybinding.
  • Currently disabled for window.position = "float"
    • With the floating window, it looks awkward after resizing the window.
    • Therefore, I currently disable this feature on floating window.
    • Floating windows tend to have a wider width by default and I find myself rarely overflowing the width in the first place. (Fig: tested on floating windows; The right side of the window is kinda broken.)
      Screenshot_20221024_170959

I hope this helps,
pysan3

@cseickel
Copy link
Contributor

Hi, I love the extensibility of this plugin.

Thanks!

Window width of the lines above the very-long-file-name.txt is not updated

  • This is pretty much impossible to fix because the length of lines are calculated on the fly.
  • Not a big problem since it will get fixed by renderer.redraw(state),

You can just call renderer.redraw() a second time after you have determined and set the correct width.

  • The default keybind e conflicts with example.window.example_command?

Don't worry about that. That's just an example for devs to see how sources work. You can just move that to another unused binding.


I was originally picturing a floating window popup that shows the full name of a truncated item on hover. Have you thought about that? It is a standard way of handling this situation in other apps.

If we do stick with auto expand, I would keep track of the width prior to the auto expand instead of just using the default value from the settings. I know I will usually adjust the width manually after opening to fit different projects and screen sizes.

@codecov
Copy link

codecov bot commented Oct 25, 2022

Codecov Report

Merging #580 (9fbb66e) into main (9f5119a) will decrease coverage by 1.10%.
The diff coverage is 43.75%.

@@            Coverage Diff             @@
##             main     #580      +/-   ##
==========================================
- Coverage   51.59%   50.49%   -1.11%     
==========================================
  Files          47       47              
  Lines        5915     6092     +177     
==========================================
+ Hits         3052     3076      +24     
- Misses       2863     3016     +153     
Impacted Files Coverage Δ
lua/neo-tree/sources/common/commands.lua 7.52% <0.00%> (-0.66%) ⬇️
lua/neo-tree/ui/renderer.lua 70.04% <60.00%> (-0.82%) ⬇️
lua/neo-tree/sources/common/container.lua 67.03% <80.00%> (+0.17%) ⬆️
lua/neo-tree/defaults.lua 96.96% <100.00%> (+0.07%) ⬆️
lua/neo-tree/sources/common/preview.lua 10.22% <0.00%> (-7.64%) ⬇️
lua/neo-tree/sources/filesystem/lib/fs_scan.lua 71.95% <0.00%> (-5.06%) ⬇️
lua/neo-tree/ui/popups.lua 56.79% <0.00%> (-2.04%) ⬇️
lua/neo-tree/sources/filesystem/lib/fs_watch.lua 16.43% <0.00%> (-1.75%) ⬇️
lua/neo-tree/utils.lua 47.57% <0.00%> (-0.70%) ⬇️
... and 10 more

Help us with your feedback. Take ten seconds to tell us how you rate us. Have a feature suggestion? Share it here.

@pysan3
Copy link
Collaborator Author

pysan3 commented Oct 25, 2022

You can just call renderer.redraw() a second time after you have determined and set the correct width.

I tried to do this but as far as I had not mistaken something, it goes into an infinite recursive function call and results to an error.

Don't worry about that. That's just an example for devs to see how sources work. You can just move that to another unused binding.

1f32cda : Changed to <C-e>

I was originally picturing a floating window popup that shows the full name of a truncated item on hover. Have you thought about that? It is a standard way of handling this situation in other apps.

  • First of all, I thought it was easier to implement it this way rather than managing a floating popup for each cursor move.
  • I didn't know other apps do it with popups (do you mean other plugins like nvimtree? or IDEs like VSCode?), but I think expanding the viewer makes more sense because I see many people manually dragging the window edge and expand it to see the whole name.
  • Actually I just wanted to implement this for me, and since I don't think the two features conflict, we might be able to implement both ways.

I would keep track of the width prior to the auto expand instead of just using the default value from the settings.

I once thought about this but currently it is difficult.
With the current implementation, the window is not expanded at once (based on the longest line), but it is expanded each time there is not enough width.
So, for example if the file structure is as below and the initial width is like 5, the window width is increased for each row since the line gets longer. Since the width changes on each line, the previous width on bar.txt is what was set on foo/ and not 5.

hoge/
  fuga/
    foo/
      bar.txt

@cseickel
Copy link
Contributor

You can just call renderer.redraw() a second time after you have determined and set the correct width.

I tried to do this but as far as I had not mistaken something, it goes into an infinite recursive function call and results to an error.

You would just have to keep track of it in the state variable. Something like state.render_pass = "first" on the initial pass to get the ideal size. Then at the end of render if state.render_pass == "first", change it to state.render_pass = "second" and do one more render to get the right aligned icons correct.

Another option is that you can take advantage of state.longest_node, which I estimate for the purpose of right aligning symbols when opened in "current" position. That is a rough estimate right now but it only requires one pass and is known before render. It's currently used here here:

local remaining_cols = state.win_width
if state.current_position == "current" then
remaining_cols = math.min(remaining_cols, state.longest_node)
end

But you can use it earlier to just change the window size before this point when auto width is on.

I was originally picturing a floating window popup that shows the full name of a truncated item on hover. Have you thought about that? It is a standard way of handling this situation in other apps.

  • First of all, I thought it was easier to implement it this way rather than managing a floating popup for each cursor move.

It's definitely easier the way you are doing it.

  • I didn't know other apps do it with popups (do you mean other plugins like nvimtree? or IDEs like VSCode?),

I mean gui apps like VSCode.

  • Actually I just wanted to implement this for me, and since I don't think the two features conflict, we might be able to implement both ways.

Fair enough. In that case I would make sure the option is renamed and the value is a string rather than a boolean so it can be a three state option to expand the width of the window, show a float, or do nothing.

I would keep track of the width prior to the auto expand instead of just using the default value from the settings.

I once thought about this but currently it is difficult. With the current implementation, the window is not expanded at once (based on the longest line), but it is expanded each time there is not enough width.

I feel like there must be a way to logically distinguish between a user change and your changes, but maybe it's not worth the effort to do so. Don't worry about it.

@pysan3
Copy link
Collaborator Author

pysan3 commented Nov 20, 2022

Sorry for the late update but I revised the code quite a lot and I think I was able to fix most of the bugs and issues.

One warning is that you should call render_tree(state) instead of state.tree:render() due to the fact that it needs to check the width after the rendering the whole tree.
It cannot be done only with state.tree:render() because in that case, Nuitree calls prepare_node (render.lua) for each row and that's the only place to decide the width. I could not find kinda POST_RENDER hook that can be attached to Nuitree.

@cseickel
Copy link
Contributor

cseickel commented Nov 20, 2022

One warning is that you should call render_tree(state) instead of state.tree:render() due to the fact that it needs to check the width after the rendering the whole tree.

No problem, that was a nice solution to the problem. There is one more place to replace tree:render() though:

M.expand_to_node = function(tree, node)
if type(node) == "string" then
node = tree:get_node(node)
end
local parentId = node:get_parent_id()
while parentId do
local parent = tree:get_node(parentId)
parent:expand()
parentId = parent:get_parent_id()
end
tree:render()
end

I tested it out and I think it works well. The only other left to do is to add some documentation about the new feature to the help file and add the mapping in the README's Quickstart section.

@pysan3
Copy link
Collaborator Author

pysan3 commented Nov 20, 2022

I know that line but I think there's no need to call render_tree in that situation.

Possible change in width only happens when opening a new window with auto_expand_width == true in the first place, or toggling between true and false with keybind (e).

Therefore, I couldn't think of any situation of needing to change width with that tree:render().
Am I right?

But in any cases, I think it's not difficult to change to expand_to_node(state, node) because this function is only referenced once.

I tested it out and I think it works well.

Thank you for testing 👍

The only other left to do is to add some documentation about the new feature to the help file and add the mapping in the README's Quickstart section.

May I hand it to you to write the docs and README because I was not sure enough where in the document I should write about this.
I think the content should be enough with what is written as a comment in defaults.lua.

config = {
  window = {
    auto_expand_width = false, -- expand the window when file exceeds the window width. does not work with position = "float"
  }
}

@cseickel
Copy link
Contributor

May I hand it to you to write the docs and README because I was not sure enough where in the document I should write about this.

Sure. Thanks for contributing!

@cseickel cseickel merged commit 290c84a into nvim-neo-tree:main Nov 21, 2022
@Kerwood
Copy link

Kerwood commented Nov 21, 2022

Nice job.. This is an awesome feature. Thanks :)

@dudicoco
Copy link

I've tried using this feature but the expanded window still cuts off the end of the file name:
Screenshot 2024-01-11 at 11 12 48

Should I open a new issue?

@cseickel
Copy link
Contributor

@dudicoco it looks like it is working fine to me, assuming "ten" is the end of the filename. You may just want to turn off character fading if you don't like that look.

You can disable character fading by adding this to your config:

        default_component_configs = {
          container = {
            enable_character_fade = false
          },

@dudicoco
Copy link

@dudicoco it looks like it is working fine to me, assuming "ten" is the end of the filename. You may just want to turn off character fading if you don't like that look.

You can disable character fading by adding this to your config:

        default_component_configs = {
          container = {
            enable_character_fade = false
          },

@cseickel the file name ends with .txt, that part is cut off.
enable_character_fade = false did not fix the issue.

@dudicoco
Copy link

@cseickel i've found out the cause for this - I have a config to add relative line numbers to the neo-tree buffer:

      require("neo-tree").setup({
        event_handlers = {
          {
            event = "neo_tree_buffer_enter",
            handler = function(arg)
              vim.cmd [[
                setlocal relativenumber
              ]]
            end,
          }
        },
      }
    )

Commenting out this block fixes the issue.
How can we have relative line numbers work properly together with auto width?

@cseickel
Copy link
Contributor

How can we have relative line numbers work properly together with auto width?

It sounds like a bug where the needed with is not accounting for the width of the line numbers. Open a bug report, or better yet, find the bug and submit a PR.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants