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

[Feature] Smart component truncation #96

Closed
famiu opened this issue Sep 20, 2021 · 51 comments
Closed

[Feature] Smart component truncation #96

famiu opened this issue Sep 20, 2021 · 51 comments
Labels
kind: feature New feature or request

Comments

@famiu
Copy link
Owner

famiu commented Sep 20, 2021

I'm willing to give this another shot. But first, we'd have to plan how truncation actually works. How do we decide when to truncate, which components to truncate, and where to truncate the components, and how do we allow the provider to affect the truncation? We need to plan out a good blueprint for truncation before we can implement it, so I'd like the input of as many people as possible.

@ram02z you seemed to have ideas for truncation as well, I'd be interested in hearing them out again. @Melkster how would you want truncation to work?

@famiu famiu added the kind: feature New feature or request label Sep 20, 2021
@famiu famiu changed the title [Feature] Smart component truncation for Feline [Feature] Smart component truncation Sep 20, 2021
@ram02z
Copy link
Contributor

ram02z commented Sep 20, 2021

The way I would approach truncation would require a slight refactor and breaking changes for the provider key. In order for the truncation to be useful, it will have to be a core feature, so you can't really opt out. Firstly, we would have to store the state of the statusline. The main elements we would require for truncation would be the remaining length of the section (assuming that sections are equal in length), the current window size and the truncation priority. The priority system will be important as it will allow us to know what components need to be truncated, therefore, it should have its own key for components where the user can change the priority of component. If the component doesn't have a priority set, it will just be left to right (index 1..N). Now, in order for the truncation to be useful, I propose three states: normal, short and hidden. This would require a seperate provider for the short version, if the user omits the short provider, the provider will just get hidden. Therefore, feline will first compare the current window length and the remaining section length and use that to either show the full provider, the short provider or just hide it entirely. I think this method is better than the max_length method because that is quite naive since it just splits the string if it is greater than N characters. Also, I don't think you have to worry about the fact that neovim doesn't have a WinResized autocommand since the statusline is smart enough to update when the window is resized (you can try this out by using the enabled key to query the window size)

@famiu
Copy link
Owner Author

famiu commented Sep 21, 2021

The way I would approach truncation would require a slight refactor and breaking changes for the provider key. In order for the truncation to be useful, it will have to be a core feature, so you can't really opt out. Firstly, we would have to store the state of the statusline. The main elements we would require for truncation would be the remaining length of the section (assuming that sections are equal in length), the current window size and the truncation priority. The priority system will be important as it will allow us to know what components need to be truncated, therefore, it should have its own key for components where the user can change the priority of component. If the component doesn't have a priority set, it will just be left to right (index 1..N). Now, in order for the truncation to be useful, I propose three states: normal, short and hidden. This would require a seperate provider for the short version, if the user omits the short provider, the provider will just get hidden. Therefore, feline will first compare the current window length and the remaining section length and use that to either show the full provider, the short provider or just hide it entirely. I think this method is better than the max_length method because that is quite naive since it just splits the string if it is greater than N characters. Also, I don't think you have to worry about the fact that neovim doesn't have a WinResized autocommand since the statusline is smart enough to update when the window is resized (you can try this out by using the enabled key to query the window size)

Maybe we could instead add a short_provider component value that takes in another function, but then that'd mean we'd have to create short versions of the built-in providers which can be annoying. Maybe make the providers take an is_short boolean value optionally and act on it? But then we wouldn't have a way to know if the provider actually uses that value or not and whether to hide it if it doesn't. So what way do you think the the short provider should be provided?

@famiu
Copy link
Owner Author

famiu commented Sep 21, 2021

Another way would be to allow provider to be a table instead of just a string. The table could work be like this:

{
   str = 'insert string here'
   short_str = 'insert short string here'
   icon = 'insert icon here'
}

But then the issue with that is then we'd have two places where the user could place icon values, the component (which takes higher precedence) and the provider itself. But we need both of them since providers need to be able to return default icons to use and components need to be able to override them. Alternatively we could also have the functions return 3 values, but that'd require reordering to put the short_str as the second return value and icon as the third. But I guess both of these would be breaking changes anyway

@mawkler
Copy link

mawkler commented Sep 21, 2021

Here my ideas on truncation behaviour that are somewhat similar to @ram02z's:

  1. The ability to specify what side to truncate (i.e. whether to cut off the right or the left part of the component).
  2. The ability to specify one ore more "shorter versions" of a component. For instance, I personally like to have the current working path in my statusline, and I have specified in the provider that it should use pathshorten() on the path when the window is narrow.
  3. The ability for feline to start truncating when the components no longer fit in the statusline rather than when the window width falls below a certain threshold. Also, if one could provide a truncation priority value to each component, feline could start truncating components from lowest to highest priority until all components fit in the statusline, and then stop truncating the remaining (highest priority) components. That way one could potentially have a mix of "short version" and "full version" components. If only one version of a provider is specified feline would truncate by cutting off the lowest priority components from the side specified by the truncation side from (1).

I'm unsure how challenging this would be to implement though, so perhaps it's too difficult.

@famiu
Copy link
Owner Author

famiu commented Sep 21, 2021

Here my ideas on truncation behaviour that are somewhat similar to @ram02z's:

  1. The ability to specify what side to truncate (i.e. whether to cut off the right or the left part of the component).

  2. The ability to specify one ore more "shorter versions" of a component. For instance, I personally like to have the current working path in my statusline, and I have specified in the provider that it should use pathshorten() on the path when the window is narrow.

  3. The ability for feline to start truncating when the components no longer fit in the statusline rather than when the window width falls below a certain threshold. Also, if one could provide a truncation priority value to each component, feline could start truncating components from lowest to highest priority until all components fit in the statusline, and then stop truncating the remaining (highest priority) components. That way one could potentially have a mix of "short version" and "full version" components. If only one version of a provider is specified feline would truncate by cutting off the lowest priority components from the side specified by the truncation side from (1).

I'm unsure how challenging this would be to implement though, so perhaps it's too difficult.

I'd say I agree with it for the most part. As for (1) though, pretty sure that would be controlled by the provider itself if we are to implement truncation. As for (2), how do you suggest for that to be implemented @Melkster?

@mawkler
Copy link

mawkler commented Sep 21, 2021

As for (2), how do you suggest for that to be implemented @Melkster?

I'm thinking that perhaps the provider field could be overloaded to also take a list of providers with decrementing length where the first element is the longest version and the last element is the shortest.

Alternatively, an optional short_provider field like you mentioned in an earlier comment.

@ram02z
Copy link
Contributor

ram02z commented Sep 21, 2021

Maybe we could instead add a short_provider component value that takes in another function, but then that'd mean we'd have to create short versions of the built-in providers which can be annoying. Maybe make the providers take an is_short boolean value optionally and act on it? But then we wouldn't have a way to know if the provider actually uses that value or not and whether to hide it if it doesn't. So what way do you think the the short provider should be provided?

Yeah, short_provider would be a seperate optional field that when omitted means that the provider is hidden when there is no space left on the bar.

I'm thinking that perhaps the provider field could be overloaded to also take a list of providers with decrementing length where the first element is the longest version and the last element is the shortest.

Overloading the provider field is also reasonable, however, not having a set limit of providers per component can result in ambigious behaviour.

@famiu
Copy link
Owner Author

famiu commented Sep 21, 2021

Yeah, short_provider would be a seperate optional field that when omitted means that the provider is hidden when there is no space left on the bar.

But wouldn't that mean that for built-in providers, we'd have to have 2 functions for each? That'd increase redundancy wouldn't it? Not to mention that the user might want different configuration options for the two providers. For example, for the file_info provider, they might want to set the file name type to full-path while for the short provider they might want short-path, how would we handle that?

@ram02z
Copy link
Contributor

ram02z commented Sep 21, 2021

But wouldn't that mean that for built-in providers, we'd have to have 2 functions for each?

That could be an advantage for choosing to overload the provider field.

Not to mention that the user might want different configuration options for the two providers. For example, for the file_info provider, they might want to set the file name type to full-path while for the short provider they might want short-path, how would we handle that?

You bring up a good example. I think for this feature to work builtin providers will need a refactor regarding their special component values. Instead, the component values will have to be specified directly from the provider i.e.

{
  provider = {
    "file_info",
    colored_icon = false,
    type = "full-path",
  },
}

Now this approach would require a refactor for the respective providers. We would need to check if the provider is a table or a string. If it is a table, we expect component values. If it is a string, we fallback to the provider's default configuration.

Following this approach, the user could also define a short_provider value that has the type short-path instead.

@famiu
Copy link
Owner Author

famiu commented Sep 21, 2021

But wouldn't that mean that for built-in providers, we'd have to have 2 functions for each?

That could be an advantage for choosing to overload the provider field.

I don't get what you mean by that.

Not to mention that the user might want different configuration options for the two providers. For example, for the file_info provider, they might want to set the file name type to full-path while for the short provider they might want short-path, how would we handle that?

You bring up a good example. I think for this feature to work builtin providers will need a refactor regarding their special component values. Instead, the component values will have to be specified directly from the provider i.e.

{
  provider = {
    "file_info",
    colored_icon = false,
    type = "full-path",
  },
}

Now this approach would require a refactor for the respective providers. We would need to check if the provider is a table or a string. If it is a table, we expect component values. If it is a string, we fallback to the provider's default configuration.

Following this approach, the user could also define a short_provider value that has the type short-path instead.

What about icons then, would they be a provider value or a component value?

@famiu
Copy link
Owner Author

famiu commented Sep 21, 2021

Also, what if every component gets truncated and the statusline still isn't small enough to fit within the window? Do we just let Neovim deal with that like it currently does?

@ram02z
Copy link
Contributor

ram02z commented Sep 21, 2021

That could be an advantage for choosing to overload the provider field.

I don't get what you mean by that.

I was refering to one of @Melkster's ideas. He suggested overloading the provider function.

His full response:
"I'm thinking that perhaps the provider field could be overloaded to also take a list of providers with decrementing length where the first element is the longest version and the last element is the shortest."

What about icons then, would they be a provider value or a component value?

Icons would remain as a component value. I think having a different icon for normal and short providers doesn't make much sense since the short provider's usecase is just to provide a shorter alternative to the normal provider.

@ram02z
Copy link
Contributor

ram02z commented Sep 21, 2021

Also, what if every component gets truncated and the statusline still isn't small enough to fit within the window? Do we just let Neovim deal with that like it currently does?

We shouldn't really factor in window sizes that are too small to have a statusline since they won't be realistic. If the statusline is too small to fit anything and everything is truncated, then we can only assume the window is too small to fit anything anyway.

@famiu
Copy link
Owner Author

famiu commented Sep 21, 2021

So, is that all? If so, I can probably start work on implementing it

@ram02z
Copy link
Contributor

ram02z commented Sep 21, 2021

Yeah, maybe start on refactoring the special component values for builtin providers first before starting to work on the truncation feature.

@famiu
Copy link
Owner Author

famiu commented Sep 21, 2021

@ram02z so, another issue, some providers (eg: vi_mode) still reference component.icon in their provider, if we only send the provider table values to the provider function (which I personally think should be the case), we'd somehow need to have a deal with that. One way is to remove the vi_mode provider entirely since it just shows an icon anyway. Another way is to send both the provider table and the component table to the provider function, which I personally believe is too much

@ram02z
Copy link
Contributor

ram02z commented Sep 21, 2021

One way is to remove the vi_mode provider entirely since it just shows an icon anyway.

Vi mode has very basic implementation, however, it is probably used in every config, so I don't think it should be deprecated.

Another way is to send both the provider table and the component table to the provider function, which I personally believe is too much

Couldn't you just pass the component.icon in addition to the provider table values?

@famiu
Copy link
Owner Author

famiu commented Sep 21, 2021

One way is to remove the vi_mode provider entirely since it just shows an icon anyway.

Vi mode has very basic implementation, however, it is probably used in every config, so I don't think it should be deprecated.

That's true, however, it's worth noting that Feline isn't at version 1.0 yet, as long as the deprecation period is long enough, it shouldn't cause any problems. Besides, all the user would have to do is the change the provider string from 'vi_mode' to their preferred icon. We could also turn the get_vim_mode() utility function in the vi_mode provider file to a vi_mode_name provider for those that don't use icons.

Another way is to send both the provider table and the component table to the provider function, which I personally believe is too much

Couldn't you just pass the component.icon in addition to the provider table values?

Passing just the icon just seems like a wrong design choice imo, I'd say either pass the entire component table or none of it.

@famiu
Copy link
Owner Author

famiu commented Sep 21, 2021

Oh, I just thought of a way. It would be possible to make the vi_mode provider just return an icon with highlight instead of the provider text. The issue with that is that currently the icon is not shown if the provider is empty. Maybe an always_visible option for icons?

@ram02z
Copy link
Contributor

ram02z commented Sep 21, 2021

Can vim.api.nvim_get_mode() return nil?

@famiu
Copy link
Owner Author

famiu commented Sep 21, 2021

Can vim.api.nvim_get_mode() return nil?

Don't think so, no. Besides, get_vim_mode() in the vi_mode does provider doesn't just use nvim_get_mode, it actually shows an alias for the mode

@mawkler
Copy link

mawkler commented Sep 21, 2021

@famiu

Also, what if every component gets truncated and the statusline still isn't small enough to fit within the window? Do we just let Neovim deal with that like it currently does?

This is why I suggested giving each component a priority and a truncation direction (i.e. left or right side). When this situation occurs, Feline can start removing the lowest priority component until all remaining ones fit. Now the last component to be removed can get truncated based on its truncation direction and the remaining part of it could be rendered in the statusline as well.

@famiu
Copy link
Owner Author

famiu commented Sep 22, 2021

By the way, there's one last issue we need to tackle, how do we find the length of a component? Simply using the string's length won't work since not all of it is displayed on the statusline and some of it is parsed by Neovim

@ram02z
Copy link
Contributor

ram02z commented Sep 22, 2021

By the way, there's one last issue we need to tackle, how do we find the length of a component? Simply using the string's length won't work since not all of it is displayed on the statusline and some of it is parsed by Neovim

Using the return value of the provider should work, since none of the builtin providers return any statusline modifiers and we don't expect users to return statusline modifiers in their custom providers either. The logic will have to come after this line:

local str, icon = parse_provider(component.provider, component, winid)

@famiu
Copy link
Owner Author

famiu commented Sep 22, 2021

By the way, there's one last issue we need to tackle, how do we find the length of a component? Simply using the string's length won't work since not all of it is displayed on the statusline and some of it is parsed by Neovim

Using the return value of the provider should work, since none of the builtin providers return any statusline modifiers and we don't expect users to return statusline modifiers in their custom providers either. The logic will have to come after this line:

local str, icon = parse_provider(component.provider, component, winid)

But then, things like icons and separators could still cause the statusline text to be larger than the window

@ram02z
Copy link
Contributor

ram02z commented Sep 22, 2021

But then, things like icons and separators could still cause the statusline text to be larger than the window

Damn, I forgot that icons and seperators return statusline modifiers. Unforunately there isn't a function like expand for evaluating the statusline, however, we can assume that both parse_icon and parse_sep return a string that has a highlight prepended.

%#StatusComponent_FF79C6_21222C_NONE# + is an example of the string returned by parse_icon. We could use vim.split to split the string at # and get the last string, which would be + in our example. I think once the provider, icon and seperators have been evaluated we pass them indivually to a function that splits each of them like above and returns the combined length of the strings.

local function component_len(str, ...)
  local len = #str
  local next = next
  local spl

  for _, arg in ipairs {...} do
    if type(arg) == "string" and arg ~= "" then
      spl = vim.split(arg, "#")
      if next(spl) then
        spl = spl[#spl]
        len = len + #spl
      end
    end
  end

  return len
end

You could call the function before parse_component's return statement i.e. component_len(str, left_sep_str, right_sep_str, icon)

@famiu
Copy link
Owner Author

famiu commented Sep 22, 2021

But then, things like icons and separators could still cause the statusline text to be larger than the window

Damn, I forgot that icons and seperators return statusline modifiers. Unforunately there isn't a function like expand for evaluating the statusline, however, we can assume that both parse_icon and parse_sep return a string that has a highlight prepended.

%#StatusComponent_FF79C6_21222C_NONE# + is an example of the string returned by parse_icon. We could use vim.split to split the string at # and get the last string, which would be + in our example. I think once the provider, icon and seperators have been evaluated we pass them indivually to a function that splits each of them like above and returns the combined length of the strings.

local function component_len(str, ...)
  local len = #str
  local next = next
  local spl

  for _, arg in ipairs {...} do
    if type(arg) == "string" and arg ~= "" then
      spl = vim.split(arg, "#")
      if next(spl) then
        spl = spl[#spl]
        len = len + #spl
      end
    end
  end

  return len
end

You could call the function before parse_component's return statement i.e. component_len(str, left_sep_str, right_sep_str, icon)

Alternatively, we could make parse_icon and parse_sep_list return their length without the highlight to avoid all that extra pre-processing

@famiu
Copy link
Owner Author

famiu commented Sep 22, 2021

I just realized that file_info still requires component.icon so even if we do refactor vi_mode that still leaves us with an issue

@ram02z
Copy link
Contributor

ram02z commented Sep 22, 2021

I just realized that file_info still requires component.icon so even if we do refactor vi_mode that still leaves us with an issue

Couldn't you just pass component.icon to the builtin providers?

@famiu
Copy link
Owner Author

famiu commented Sep 22, 2021

I just realized that file_info still requires component.icon so even if we do refactor vi_mode that still leaves us with an issue

Since removing the dependence for the component table is out of the question, I propose that we allow provider to take 3 arguments instead, opts for the provider options, component for the component values and winid. And yes, while that would be a massive breaking change for custom providers, not many people really use custom providers plus since all of this will be released in Version 0.2 anyway, I think people will have time to change their configurations.

@famiu
Copy link
Owner Author

famiu commented Sep 22, 2021

I just realized that file_info still requires component.icon so even if we do refactor vi_mode that still leaves us with an issue

Couldn't you just pass component.icon to the builtin providers?

Again, I'm against passing just the icon. What if we eventually need the highlight, do we add yet another argument for it? What if we need the separators? You can see that that could be a big problem. Either we have no dependence on the component or just take the whole component

@ram02z
Copy link
Contributor

ram02z commented Sep 22, 2021

Again, I'm against passing just the icon. What if we eventually need the highlight, do we add yet another argument for it? What if we need the separators? You can see that that could be a big problem. Either we have no dependence on the component or just take the whole component

Well for the meantime there are no builtin providers that utilise component values other than the icon and special component values. If you do eventually need the highlight or another component value, you can go back to using the component table. Honestly, I am not too fussed about passing the full component table.

@famiu
Copy link
Owner Author

famiu commented Sep 22, 2021

Again, I'm against passing just the icon. What if we eventually need the highlight, do we add yet another argument for it? What if we need the separators? You can see that that could be a big problem. Either we have no dependence on the component or just take the whole component

Well for the meantime there are no builtin providers that utilise component values other than the icon and special component values. If you do eventually need the highlight or another component value, you can go back to using the component table. Honestly, I am not too fussed about passing the full component table.

Wouldn't it be better to just do it right away then instead of having yet another breaking change in the future changing what arguments the provider takes?

@ram02z
Copy link
Contributor

ram02z commented Sep 22, 2021

Wouldn't it be better to just do it right away then instead of having yet another breaking change in the future changing what arguments the provider takes?

Yeah you could definitely do it right away, but it won't be a breaking change, since changing the arguments for the builtin providers won't affect the user.

@famiu
Copy link
Owner Author

famiu commented Sep 22, 2021

Wouldn't it be better to just do it right away then instead of having yet another breaking change in the future changing what arguments the provider takes?

Yeah you could definitely do it right away, but it won't be a breaking change, since changing the arguments for the builtin providers won't affect the user.

Changing the arguments for builtin providers changes them for all providers since all providers are treated the same way, so it would in fact be a breaking change

@ram02z
Copy link
Contributor

ram02z commented Sep 22, 2021

Changing the arguments for builtin providers changes them for all providers since all providers are treated the same way, so it would in fact be a breaking change

Aren't custom providers and builtin providers are handled seperately? You could just change the arguments for builtin providers without affecting custom providers.

if type(provider) == "string" and type(providers[provider]) == "function" then
provider, icon = providers[provider](component, winid)
elseif type(provider) == "function" then
provider, icon = provider(component, winid)
end

@famiu
Copy link
Owner Author

famiu commented Sep 22, 2021

Changing the arguments for builtin providers changes them for all providers since all providers are treated the same way, so it would in fact be a breaking change

Aren't custom providers and builtin providers are handled seperately? You could just change the arguments for builtin providers without affecting custom providers.

if type(provider) == "string" and type(providers[provider]) == "function" then
provider, icon = providers[provider](component, winid)
elseif type(provider) == "function" then
provider, icon = provider(component, winid)
end

They are, but I'm against handling them separately. I think all providers should allow the same level of customizability. Especially since providers can be added using add_provider

@ram02z
Copy link
Contributor

ram02z commented Sep 22, 2021

They are, but I'm against handling them separately. I think all providers should allow the same level of customizability. Especially since providers can be added using add_provider

If they are going to be handled the same, then special component values being moved to the provider wouldn't make sense for custom providers because they have no special component values.

@famiu
Copy link
Owner Author

famiu commented Sep 22, 2021

They are, but I'm against handling them separately. I think all providers should allow the same level of customizability. Especially since providers can be added using add_provider

If they are going to be handled the same, then special component values being moved to the provider wouldn't make sense for custom providers because they have no special component values.

I mean, theoretically speaking, a custom provider can be the same function that's used in two different places (eg: the active and inactive statusline) but with different options

@famiu
Copy link
Owner Author

famiu commented Sep 24, 2021

So, two major issues:

  1. When a wide character is used (such as some of the icon glyphs that are used in many providers) in a string and its length is accessed, the wide character counts as 2 characters instead of 1, which messed up truncation.

  2. Truncation seems to add an unbelievably high amount of complexity to the code. Like I knew it'd make the code more complex but I didn't imagine it'd be to that extent.

Honestly, things are looking dim for the truncation feature request now, it's just way too much effort at this point.

@ram02z
Copy link
Contributor

ram02z commented Sep 24, 2021

  1. When a wide character is used (such as some of the icon glyphs that are used in many providers) in a string and its length is accessed, the wide character counts as 2 characters instead of 1, which messed up truncation.

I wouldn't call that an issue for feline. It could be different depending on the terminal emulator you use.

  1. Truncation seems to add an unbelievably high amount of complexity to the code. Like I knew it'd make the code more complex but I didn't imagine it'd be to that extent.

Honestly, things are looking dim for the truncation feature request now, it's just way too much effort at this point.

I didn't expect truncation to have an easy implementation, which is why I suggested that it be implemented as a core feature. If you decide not to complete it, it would be very useful to submit your current work as a draft PR, so I (or someone interested) can pick up from where you left off.

@famiu
Copy link
Owner Author

famiu commented Sep 24, 2021

  1. When a wide character is used (such as some of the icon glyphs that are used in many providers) in a string and its length is accessed, the wide character counts as 2 characters instead of 1, which messed up truncation.

I wouldn't call that an issue for feline. It could be different depending on the terminal emulator you use.

It is an issue for Feline because the character still only takes 1 character width of space in the window, but since it uses multiple bytes (or at least that's why I think it happens) it counts as multiple characters in the string. Couple that with the fact that the glyphs are used literally everywhere in Feline, and I'd say that's a pretty big problem, honestly.

I didn't expect truncation to have an easy implementation, which is why I suggested that it be implemented as a core feature. If you decide not to complete it, it would be very useful to submit your current work as a draft PR, so I (or someone interested) can pick up from where you left off.

I could do that, yes. But the issue is not that the implementation is hard. The issue is that the implementation is going to be flawed (doesn't work with Vim statusline modifiers or with multibyte characters) and it'll greatly increase the complexity of the codebase which can make the code borderline unreadable for anyone who's willing to contribute

@ram02z
Copy link
Contributor

ram02z commented Sep 24, 2021

It is an issue for Feline because the character still only takes 1 character width of space in the window, but since it uses multiple bytes (or at least that's why I think it happens) it counts as multiple characters in the string. Couple that with the fact that the glyphs are used literally everywhere in Feline, and I'd say that's a pretty big problem, honestly.

I am sorry, but I think I am missing the issue. If a double width glyph counts as 2 characters, wouldn't that mean that feline would calculate the length correctly? If it takes one visible cell width then it is because of your terminal emulator.

@famiu
Copy link
Owner Author

famiu commented Sep 24, 2021

It is an issue for Feline because the character still only takes 1 character width of space in the window, but since it uses multiple bytes (or at least that's why I think it happens) it counts as multiple characters in the string. Couple that with the fact that the glyphs are used literally everywhere in Feline, and I'd say that's a pretty big problem, honestly.

I am sorry, but I think I am missing the issue. If a double width glyph counts as 2 characters, wouldn't that mean that feline would calculate the length correctly? If it takes one visible cell width then it is because of your terminal emulator.

Sorry, it's not double width, wrong wording on my part. I meant multibyte not double-width.

@famiu
Copy link
Owner Author

famiu commented Sep 25, 2021

vim.fn.strdisplaywidth seems to solve this issue

@famiu
Copy link
Owner Author

famiu commented Sep 25, 2021

How would I go about adding truncation directions for specific components like what @Melkster wants? Like, what's the Vim statusline syntax for truncating a specific section of the statusline from a specific direction. Because as far as I can see, %< can only be used once in the statusline string

@ram02z
Copy link
Contributor

ram02z commented Sep 25, 2021

vim.fn.strdisplaywidth seems to solve this issue

There is also vim.api.nvim_strwidth

@ram02z
Copy link
Contributor

ram02z commented Sep 25, 2021

How would I go about adding truncation directions for specific components like what @Melkster wants? Like, what's the Vim statusline syntax for truncating a specific section of the statusline from a specific direction. Because as far as I can see, %< can only be used once in the statusline string

Well, I don't think feline should cut strings, rather leave that to the user when setting a short provider. This behaviour is inspired by the formatting used for blocks in i3status-rust.
See https://github.com/greshake/i3status-rust/blob/master/doc/blocks.md#formatting for more information.

@famiu
Copy link
Owner Author

famiu commented Sep 25, 2021

vim.fn.strdisplaywidth seems to solve this issue

There is also vim.api.nvim_str_width

That function doesn't seem to exist on my version of Neovim.
EDIT: Nvm, it's called nvim_strwidth

How would I go about adding truncation directions for specific components like what @Melkster wants? Like, what's the Vim statusline syntax for truncating a specific section of the statusline from a specific direction. Because as far as I can see, %< can only be used once in the statusline string

Well, I don't think feline should cut strings, rather leave that to the user when setting a short provider. This behaviour is inspired by the formatting used for blocks in i3status-rust.
See https://github.com/greshake/i3status-rust/blob/master/doc/blocks.md#formatting for more information.

Makes sense

@rebelot
Copy link

rebelot commented Sep 25, 2021

I don't want to sound impolite, really I love this plugin and I think it is the best at its job.
Could you please explain to me the advantage of this feature when one can do:

provider = function(winid, component)
    if vim.fn.winwidth(winid) >= 100 then return 'looooong'
    else return 'short'
    end
end

@ram02z
Copy link
Contributor

ram02z commented Sep 25, 2021

I don't want to sound impolite, really I love this plugin and I think it is the best at its job.
Could you please explain to me the advantage of this feature when one can do:

This is basically what I do in my own config. The main advantage with the approach I described above it will (hopefully) take into account the remaining length in each section and the priority of each component to "intelligently" decide when to show, truncate or hide components.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
kind: feature New feature or request
Projects
None yet
Development

No branches or pull requests

4 participants