-
Notifications
You must be signed in to change notification settings - Fork 528
feat: dynamic modes #1464
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
base: master
Are you sure you want to change the base?
feat: dynamic modes #1464
Conversation
- Changed Telescope picker select-action to toggle (rather than just turn on) - Added default "normal" global mode - allows
…g the normal mode for a component)
|
Thanks for opening the pr. There's a lot. I'll look at the complete thing later. But I'm not yet sure we want to add something like this. This complicates the config process quite. In general my policy has been keep things flexible so complicated setups are possible but not to cater toward any specific complex setup, unless it provides a good enough premmitive with little cost. This feels like it assumes a style of config. Also, if I understand your usecases are handling floating windows and changing config based on set mode if I'm not mistaken. For the first one I'd really recommend you to try out globalstatus mode. For changing out configs on the fly based on mode, calling base = {
...
}
narrow = vim.tbl_extend('force', base, {
-- custom part that needs change for narrow config
})
wide = vim.tbl_extend('force', base, {
-- custom part that needs change for wide config
})
-- same as above. Basically separate out the configs you are trying to have in on table.Then you can do something like local current_config = 'wide' -- you can do a screenwidth check and set the default based on that
function toggle_modes()
if current_config = 'wide' then lualine.setup(narrow)
else lualine.setup(wide)
end
endYou get the idea. You can obviously instead of toggle just change to specific config through a telescope picker. Also if you need sperate style on per filetype basis you can look at lualine-extensions . you can also have custom extensions. let me know your thoughts on these. Actually allowing more flexible ways to check when an extension get's loaded would probably be a better idea then just based on filetypes. |
|
Hey, thanks for the reply. I wasn't aware that setup() could be called repeatedly like that - other plugins can be kind of finnicky in that respect. You're right though, that would accomplish the same thing that I'm looking for. I guess you could still make an argument that this feature would offer something useful by baking the dynamic setup() pattern into the lualine config itself and making the configuration(s) "horizontal" rather than "vertical" if you know what I mean. I was playing around with this config earlier today: cropped.mp4One thing I like about it is the fact that all of the configuration variations for this particular component are together in one place. But this is really a matter of stylistic preference - I can imagine someone else feeling the exact opposite way (that all of the narrow configurations should be in one place, all the medium configurations in another place, etc). This is what I mean by "vertical" vs "horizontal". No worries if you feel that the benefits don't outweigh the complexity costs (although FWIW, there is much more complexity in the feature's usage / documentation than in the implementation itself). As for |
|
I'll keep this open. If I see more interest from community then I'll consider it further but for now it's a no merge for me. Primarily for two reasons.
I understand your argument for vertical vs horizontal. But due to point 2 mentioned above I'm against it. Also, there's not sufficient reason to support horizontal approach to since vertical is already supported.
Not odd at all. That's perfectly fine. You can try out putting filename in winbar and globalstatus for the statusline if you haven't already. |
Lualine Dynamic Alternative States (ie. modes)
This extension adds syntactic sugar to lualine, allowing users to cleanly configure complex dynamic setups. With this addition, lualine will determine the current "mode" of each lualine component and dynamically select a specific configuration for that component, based on the mode.
The Problem
Lualine is already plenty flexible out of the box - a dynamic statusline is achievable by using lualine function components and condition functions.
In the simpler case, where the component displays a single value based on some condition, a lualine condition-function can be used:
Here, the
condfield is essentially syntactic sugar - Rather than specify the condition as a separate field, we could have just written the following:But having this "cond" field feels much more natural, and it adheres to the single-responsibility principle. The function that renders a component's content should be distinct from the function that decides whether or not the content should be rendered.
This new proposed feature is essentially a natural extension of these principles. I found myself wanting to write it when thinking about different lualine "modes" that I could switch between dynamically. Specifically, I wanted to change the state of lualine whenever a Telescope window was opened. Lualine doesn't really interact with Telescope directly, and there isn't any natural way to implement a Telescope extension for lualine. This is of course because Telescope deals only in floating windows (which do not have statuslines). So I had to implement something custom for my use case, and I found myself having to write lots of code that looked like this:
For even 2 cases, it's pretty verbose. And if you wanted to generalize to >2 distinct modes (ie. "short", "medium" and "long" modes designed for various window configurations / monitor setups, etc), it would get pretty hairy.
You could of course clean this logic up with something like this:
Which is a step in the right direction, but still not great. Also, if you want to change the colors in the same dynamic way, you would need to repeat all the same logic in the
colorfield of the component options, defining variables likeLUALINE_A_1_COLORS, etc... Not great.Ultimately, if a user wants to achieve this functionality, they need to write their own custom implementation which will likely look strange in some way or another.
One thing I love about lualine is the natural readability of its configuration. So I thought it might be good to offer this dynamic functionality out of the box in a more declarative way.
The Solution - Dynamic Modes
This feature is composed of two things:
API
Modes can be set for a specific component, or globally. The global mode serves as a fallback - if no mode is set for a component, then the global mode will be used.
To set a mode for a specific component:
To set a mode globally:
To clear a mode for a specific component:
Note: This causes getMode(componentName) to return the global mode
To clear the global mode:
The global mode can be "set to nil", but the global mode cannot actually ever be nil.
As a fallback, the global mode (and by extension each unset component mode) evaluates to
normalwhen no mode is setAliasing
condwithaltModesThe simplest way to use this feature is essentially as an alias for the
condfield. By specifying an array ofaltModes, we can tell lualine to display this component only when at least one of these modes is turned on.See this configuration example:
With this configuration, an inactive window will appear like so, in the absence of any modes.
When the
telescopeFilesmode is set, the inactive windows appear like so:Notice the telescope icon, the eyeball icon, and the git logo icon in the bottom right corner of each inactive window.
Negations
Optionally, altModes can be prefixed with "!" to specify that any mode except the listed
altModeswill cause the component to be rendered. For example, the configurationaltModes = {"!myMode"}will cause the component to disappear whenever its mode is set to "myMode". Similarly, a component can be made to appear whenever any mode has been set by specifyingaltModes = {"!normal"}Note that the altModes prefixed with "!" function as an AND gate, and the normal altModes function as an OR gate.
Arbitrary Per-Mode Configurations
The cond alias is nice, but we can also express more complex logic. Suppose you want to tweak the display of a component according to its mode, rather than just turning it on/off.
To do this, you can specify a map of
alts(alternative configuration values) to the component's options. For example:This configuration creates a filename component which changes to one of 4 states, based on the current mode.
Notice that modes 2 and 3 override the
pathparameter, and none of the modes define thefile_statusparameter. By default, the base component's configuration values are inherited by its alternative states unless overridden. You can think of it as a parent-child relationship.These particular configurations are obviously trivial, but they serve as a good visual example of the feature's capabilities.
Here is a more practical example:
When the
shortmode is set, this component will render as a lualine function component with a custom output (the first letter of the current input mode - "V" for "Visual", "N" for "Normal", etc). If this component's mode is anything other thanshort, the component will display the builtin lualine "mode" component (the full word, rather than the first letter).demo.mp4
Additional Features
For experimentation and demoing purposes a Telescope picker is provided to cycle between modes.
Selecting an entry in the picker will toggle the global mode between the selected entry and the
normalmode.The inactive_sections portion of your config will receive live updates as you interact with the picker.
Telescope must be closed to view the active_sections portion however (unless the tabline/winbar is used).
This is why I've mostly used the inactive_sections in the demo materials.
Implementation Details
The implementation is pretty lightweight. Whenever a component is instantiated, alternative configurations are constructed based on the user's configuration (the component's "base" configuration is supplemented / overridden to generate each alt configuration). These alt configurations are then used to instantiate separate components which are stored alongside the original component (each base component has an "alts" table which maps mode-names to these alternative components)
Whenever a section is rendered, we simply check whether or not an alternative component should be used in place of our base components. If so, we simply use that component in place of the base component:
The
condaliasing logic with thealtModesparameter is implemented in a completely distinct way. IfaltModesis specified, we simply wrap the component's existingcondfunction (or creating one if there no such function is declared).Developer Notes
Some of the naming conventions could definitely be cleaned up. "customPicker" is a pretty bad name for the Telescope picker (although I don't really think the picker has much purpose beyond demoing this feature - I'd be happy to remove it altogether). The commit history is a little messy as well. @nvim-lualine if you're a fan of this feature and would like it to be merged, I'm happy to clean these things up.
If this feature does end up getting approved, I'm also happy to update the docs