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: Elastic Tabstops #1419

Open
pencilcheck opened this issue Nov 6, 2014 · 26 comments
Open

Feature: Elastic Tabstops #1419

pencilcheck opened this issue Nov 6, 2014 · 26 comments
Labels
enhancement feature request
Milestone

Comments

@pencilcheck
Copy link

http://nickgravgaard.com/elastictabstops/

Would be nice if neovim could have a mode to support elastic tabstops which is I think a very good solution to the long standing tab or space problem among programmers who have to read other's source code written in other less ideal editors.

I heard that this requires modifying the vim source, would be nice if someone can take over and implement this in neovim.

@justinmk justinmk added the enhancement feature request label Nov 6, 2014
@justinmk justinmk added this to the vNext milestone Nov 6, 2014
@justinmk justinmk modified the milestones: wishlist, vNext Mar 16, 2015
@jgkamat
Copy link

jgkamat commented Apr 11, 2015

I would love it if this could be implemented! +1

@ChrisPenner
Copy link

This may be of note:
Patch for elastic tabs for classic vim: https://github.com/chrisbra/vim-mq-patches/blob/master/var_tabstops

@dougcosine
Copy link

I would also like to see this happen.

@addisonamiri
Copy link

I think it would be nicer to extend the new plugin api to allow for something like this instead of patching neovim to support it. It would allow other things of this nature to be added by plugins in the future. How difficult would it be for something to be added?

Edit: Implementing this using a new feature in the api could serve as a good reference implementation.

@justinmk
Copy link
Member

justinmk commented Oct 3, 2015

@chrisbra is pushing for inclusion of this in Vim. We will probably just wait for that.

@fmoralesc
Copy link
Contributor

@justinmk I took a look at those patches, and they are not quite the same as elastic tabstops. If In understand it correctly, this makes it so tabs are expanded a variable amount of spaces in a buffer, so

a<tab>b<tab>c<tab>d

will be displayed as

a    b    c    d

for vartabstop=4, and as

a    b          c                d

for vartabstop=4,10,16,4. This is similar to some functionality available in word processors, but I'm not sure what is point, since these stops are the same for every tabstop in the buffer (whereas elastic tabpstops depend on the context). It might "simulate" elastic stops in combination with autoindent and noexpandtab, but it certainly is not the same idea, and it looks quite a bit clunkier and uncomfortable.

@justinmk
Copy link
Member

justinmk commented Oct 4, 2015

@fmoralesc Which patches are you referring to? I am referring to a recent thread (in the last month). Maybe @chrisbra can correct me, I cannot find it.

@fmoralesc
Copy link
Contributor

I couldn't find any recent news about it, so I supposed it was the var_tabstops patches (linked above).

@fmoralesc
Copy link
Contributor

@justinmk Indeed, you must have seen this thread, which talks about vartabstops: https://groups.google.com/forum/#!topic/vim_dev/RgJ4Yj-X2a8

Is there any chance the variable tabstops patch could be included in
the next release? I wrote the first version about eight years ago,
so it's about time it made it out of todo.txt and into the released
code. I really don't understand why it keeps on being ignored when
other less-requested and far more potentially disruptive changes are
accepted straight away.

+1

I keep pushing it every once in a while.

Best,
Christian

@justinmk
Copy link
Member

justinmk commented Oct 4, 2015

@fmoralesc that is right thanks! My mistake.

@nick-gravgaard
Copy link

@fmoralesc @justinmk As far as I can see the work @chrisbra did with his var_tabstops patch will not enable anyone to implement elastic tabstops as it does not let you set non-uniform tabstops differently on different lines.

In order to implement elastic tabstops we need some way of specifying non-uniform tabstops for different lines which can be called by a scripting language when text in the buffer changes. I don't know what the most idiomatic way of specifying it in Vim might be, but you should be able to do things like specify lines 1-10 have tabstops at positions 4, 14, 30, 34 while lines 11-20 have tabstops at positions 5, 11, 17, 23 for example.

I would love to see my invention find its way to Vim. Until then, one option for people who want a vi like editor with elastic tabstops is to use Textadept with scripts to implement vi key bindings and elastic tabstops. This is possible because Textadept uses the brilliant cross-platform Scintilla text widget which I added the ability to set non-uniform tabstops to. You can see how its API works here:

SCI_CLEARTABSTOPS(int line)
SCI_ADDTABSTOP(int line, int x)
SCI_GETNEXTTABSTOP(int line, int x)
SCI_CLEARTABSTOPS clears explicit tabstops on a line. SCI_ADDTABSTOP adds an explicit tabstop at the specified distance from the left (in pixels), and SCI_GETNEXTTABSTOP gets the next explicit tabstop position set after the given x position, or zero if there aren't any.

You can see my native implementation of elastic tabstops for Scintilla (which uses this API) here.

I hope this gives someone some ideas :)

@whitelynx
Copy link

👍 I'd even love to see this as a plugin, if it is possible to implement there... Given the conceal feature (as used by AnsiEsc.vim, for instance), it seems at first glance like that might be possible, but I'd be kinda lost as to how to implement it.

@whitelynx
Copy link

I also came across https://groups.google.com/forum/#!topic/vim_dev/ax25cjxi0Vc, which is from 2012, and mentions elastic tabstops... but I'm not sure whether or not the proposed patch actually implemented them correctly. It seems there were some issues with the patch, and I can't tell whether or not it was ever revisited, but at any rate the original site where it was hosted seems to be down now.

@pencilcheck
Copy link
Author

It would be nice if neovim can implement this. That would be really cool.

@dmerejkowsky
Copy link
Contributor

Looks like the patch has been merged in vim:

A quick git log -S vartab yields:

vim/vim@04958cb
vim/vim@675e8d6
vim/vim@a87b72c
vim/vim@307ac5c

@justinmk
Copy link
Member

justinmk commented Jul 2, 2018

Need someone to port the patches to Nvim.

@justinmk justinmk modified the milestones: unplanned, todo Jul 2, 2018
@justinmk justinmk added the vim-patch See https://github.com/neovim/neovim/wiki/Merging-patches-from-upstream-Vim label Jul 2, 2018
@BatmanAoD
Copy link

@dmerejkowsky The vartab feature doesn't actually look like true elastic tabs as described by Nick Gravgaard. It seems be a manually curated list of tabstops, which is not the same thing.

@nick-gravgaard
Copy link

nick-gravgaard commented Jul 3, 2018

@BatmanAoD Sadly you are correct. As I said back in 2015 (earlier on this page), it looks like the vartabs feature lets one set non-uniform tabstops, but they are the same for all lines. That's not enough to implement elastic tabstops.

We either need a dedicated elastic tabstops mode, or the ability to implement elastic tabstops by allowing a script to set non-uniform tabstop positions differently for different lines as the user edits the text in the buffer. If the vartabs functionality can be used by a script to change tabstop positions as the user edits the text in the buffer we are half way there. I assume this is the case - can anyone confirm this is possible? If so we just need vartabs to take an extra parameter specifying the line number range.

As far as I can see, currently vartabs takes a list of tabstop sizes (eg 4, 20, 10, 8). We need to add another parameter to this so we can specify the line number range (eg. lines 7 to 13) the tabstop sizes apply to. Maybe that could be optional so if the line range parameter is missing it's applied to all lines.

In this vartabs feature one sets it like this:
:set vartabstop=4,20,10,8
What should this look like if it took (optional?) start and end line numbers? Is it possible to do something like this?
:set vartabstop=[4,20,10,8],7,13

@andypalmer
Copy link

Because vim has some semantic understanding of blocks (used for auto-indenting, as well as paragraph movement), it would probably be better to have the elastic tabstops work within a block declaratively rather than have it imperatively assign tabstops to certain lines. This would be more flexible as the content in the buffer changes.

It would probably require some coordination between syntax parsing and the buffer.

@nick-gravgaard
Copy link

@andypalmer Ah, that's interesting. Does anyone know if it's possible to make @chrisbra's vartabs code do that?

@Tarmean
Copy link

Tarmean commented Aug 19, 2019

Use case for the vim-style vartab: CSV files where columns should have different widths.

You can currently simulate this by indenting the buffer with the correct number of spaces and undoing this in BufWriteCmd but that is a lot more fragile than vartabs. Depending on the file size we might not want to recalculate the indentation on each file change anyway.

Not sure if editing non-trivial csv files/markdown tables is something neovim even wants to support, though.

@chrisbra
Copy link
Contributor

@Tarmean this would only work for tab delimited files and this is what my csv vimplugin does if it detects the vartab feature is available.

@dundargoc dundargoc added has:vim-patch issue is fixed in vim and patch needs to be ported and removed vim-patch See https://github.com/neovim/neovim/wiki/Merging-patches-from-upstream-Vim labels Dec 21, 2021
@zeertzjq zeertzjq removed the has:vim-patch issue is fixed in vim and patch needs to be ported label Dec 21, 2021
@zeertzjq
Copy link
Member

The patches mentioned in this issue have already been ported, and they do not really enable elastic tabstops.

@no-identd
Copy link

no-identd commented Dec 21, 2021

s/already/somewhat recently/
i

And I imagine that @justinmk didn't meant that #13851 would enable that on it's own (and that instead they probably meant it represents at least one of n>=1 prerequisites to implementation of elastic tabstops.), while I do suspect that the limitation you implied (can't really use the term outline) resembles the one @nickgravgaard already pointed out (your understandably terse reply sadly didn't seem to attempt to answer his question.). Anyway, I'd like to offer a proposal for a shitty hack to pass the time, which you should take as quasi-para-satircal (along with this horrible affix construction), because it's only intended to pass time, i.e. not necessarily something to take serious— like a toy model, not like a joke, but please do see the humour in it: use a file preprocessor/parser, a keylogger, a screen scanner, and a keyboard hook. At this rate it'd probably go faster to automate the feature into existence that way than to get this implemented directly, but please do avoid getting me wrong here, I mean this with respect to the complexity of the feature 🆚 the complexity of the vim codebase. I don't even use vim at the moment (which probably means that I likely messed up the syntax of the joke at the start), I just observe this issue out of great academic interest, so I have no stake here & simply wait for the puzzle pieces to slowly assemble.

@Nuc1eoN
Copy link

Nuc1eoN commented Jan 23, 2022

Hi, I just wanted to check back what the current consensus on approaching this issue would be. Have @chrisbra's patches brought us anywhere closer near a potential elastic tabstop implementation?

Or does this completely have to be retought? Is there a particular difficulty specific to vim in implementing this?

Seems with all the misunderstandings this issue ended up in an "undefined" state, so maybe it would be nice if some devs could clarify what is needed to achieve this.

@lsvmello
Copy link
Contributor

lsvmello commented Feb 6, 2024

I was able to create a plugin in lua for this using api-extended-marks: https://github.com/lsvmello/elastictabstops.nvim

It's a hack because:

  1. I couldn't find a way to get the "rendered line" and Neovim adds a different spacing for tabs. Then I took advantage of setting lcs-tab as nil then Neovim always render it as ^I.
  2. The plugin hides the ^I with an overlay extmark and then add the dynamic spacing using an inline extmark.
  3. The extmarks are build on every change. I might improve this later if needed.

Do you guys see any other way to work around those hacks?
If not I could try to implement this on Neovim directly.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement feature request
Projects
None yet
Development

No branches or pull requests