habamax / vim-asciidoctor

Asciidoctor plugin for Vim
MIT License
182 stars 16 forks source link

[Feature Request] Header Functionality Similar to Org Mode #101

Closed ossie-git closed 3 years ago

ossie-git commented 3 years ago

Hi,

I'm really loving this plugin. Thanks a lot for developing it. I'm not sure if you've run into minimd, a Markdown plugin, which is fantastic for Markdown documents. It basically incorporates some Org Mode capabilities to allow you to easily fold all headers (you can specify which header levels you want to see), quickly move around headers, demote and promote them (including sub-children), etc.

Is there any chance of seeing a similar feature in vim-asciidoctor? Thanks

habamax commented 3 years ago

vim-asciidoctor-1

habamax commented 3 years ago

btw, there is "header" text-object you can also use for copy/delete/paste whole headers ah and ih:

ossie-git commented 3 years ago

Thanks a lot. Can you also show all the headings at a given level? For example, in minimd, I can use 3<space> and it would show me the document outline up to L3 (so the entire document is folded but I can see all folds at L1, L2, and L3). This is very useful in longer documents

Here is an example of what I mean:

Screen Shot 2021-07-27 at 4 58 34 PM
habamax commented 3 years ago

Can you also show all the headings at a given level?

I don't know if vim can do it with its fold implementation, check :h fold-commands. There is also set foldlevel=1, 2, 3, etc to show fold with respected level.

ossie-git commented 3 years ago

I had a quick look and it looks like it's not supported. The minimd developer looks like he's doing something custom https://github.com/shushcat/vim-minimd/blob/master/autoload/minimd.vim

habamax commented 3 years ago

The minimd developer looks like he's doing something custom

Default vim can do smth like this too, if I get it correctly:

vim-asciidoctor-2

ossie-git commented 3 years ago

Thanks. I tried it but for some reason, while it closes some folds, it doesn't close all of them correctly

ossie-git commented 3 years ago

I ran into a very old Vim plugin that kind of does this but places the result in a different buffer. It is called folddigest. Will see if I can find another option

habamax commented 3 years ago

Thanks. I tried it but for some reason, while it closes some folds, it doesn't close all of them correctly

Looks like it works in "unexpected" way, indeed. You have to manually close all folds with zc first. zM is not enough.

habamax commented 3 years ago

You can try this too:

nnoremap <space>1 mm:%normal! zO<CR>:g/^=\{1,2}\s/normal! zc<CR>`m
nnoremap <space>2 mm:%normal! zO<CR>:g/^=\{3}\s/normal! zc<CR>`m

Add set lazyredraw if it "blinks" and maybe tune usage of the m mark if needed

ossie-git commented 3 years ago

Thanks. Tried it but it still has the same hit and miss as foldlevel

habamax commented 3 years ago

could you show me the screenshot?

ossie-git commented 3 years ago

Here's how to reproduce it. Open a document. Go to a section and open it. Go to another section and open it. Run the above mappings and it will not close all the folds. If you are standing on the fold, it will close it but not other open folds

habamax commented 3 years ago

vim-asciidoctor-3

ossie-git commented 3 years ago

Here's an example: https://raw.githubusercontent.com/asciidoctor/asciidoctor.org/main/docs/asciidoc-recommended-practices.adoc

Steps:

try to use 1 or 2. You'll notice that not both of them are closed

By the way, what application are you using for the gifs? I can record it if you want. Thanks a lot for your help.

habamax commented 3 years ago

That is screen2gif win only I think.

vim-asciidoctor-4

habamax commented 3 years ago

Following works for me:

func! FoldLevel(count) abort
    if !&foldenable
        return
    endif
    try
        let pos = getcurpos()
        silent! exe "%normal! zO"
        if a:count == 1
            silent! exe 'g/^=\{1,2}\s/normal! zc'
        else
            silent! exe 'g/^=\{'..(a:count+1)..'}\s/normal! zc'
        endif
    finally
        call setpos('.', pos)
    endtry
endfunc

nnoremap <silent> <space><tab> :<C-u>call FoldLevel(v:count1)<CR>
ossie-git commented 3 years ago

Sorry about the late reply. Was just setting up gif recording. Here is what happens when I use the shortcuts. I pressed both of them in the demo. I also tried the function you so kindly wrote and it too resulted in the same behavior

asciidoc

habamax commented 3 years ago

How do you open a fold and what is your foldlevelstart?

habamax commented 3 years ago

Maybe there is smth in your config that should be taken into account?

habamax commented 3 years ago

btw if you run on the same file with 2 open folds:

:%normal zO
:g/^=\{1,2}\s/normal! zc

would it have the same issue?

ossie-git commented 3 years ago

For your function, I noticed the following:

foldlevelstart=-1

ossie-git commented 3 years ago

Mappings

Screen Shot 2021-07-27 at 7 23 34 PM

ossie-git commented 3 years ago

These two commands you mentioned close all folds:

:%normal zO
:g/^=\{1,2}\s/normal! zc
habamax commented 3 years ago

These two commands you mentioned close all folds:

:%normal zO
:g/^=\{1,2}\s/normal! zc

Then it is strange it doesn't work for you in a mapping.

2 closes all === folds but not L2 folds

and it is implemented to do this:

== Fold opened 

bla bla

=== Fold closed
=== Fold closed
=== Fold closed

Folds are inside other folds except for the special case = -- it is treated as ==, same level.

If you want to fold only parts of the header without folding nested folds then it should be implemented this way.

== Fold closed with contents before nested folds
=== Nested fold closed
=== Nested fold closed
ossie-git commented 3 years ago

Thanks a lot for your help. I'll try to fiddle around with it to try to get it to this. Again, I really appreciate your fantastic help :)

Screen Shot 2021-07-27 at 4 58 34 PM
habamax commented 3 years ago

If you want to fold only parts of the header without folding nested folds then it should be implemented this way.

To be clear, it is not implemented, although should be fairly easy to do. Will have a look at it later. And to doublecheck, do you need it? :)

habamax commented 3 years ago

Thanks a lot for your help. I'll try to fiddle around with it to try to get it to this. Again, I really appreciate your fantastic help :)

Screen Shot 2021-07-27 at 4 58 34 PM

In this screenshot, what would happen if you add some text after ##AWS Organizations and/or ##IAM?

ossie-git commented 3 years ago

If I add some text after either of them, it would show the text but keep the other folds closed. It would hide the text if I told it to fold to a higher level (L1 in this case)

It's be a great feature to have for longer documents. I quickly tried copying of the functions used by minimd and changing them to look for = instead of # but wasn't successful. Still learning VimL basics to try to modify some plugins and add some small scripts

habamax commented 3 years ago

You have to change function that is used by foldexpr. I will try to add another option to have folds like you expect later.

ossie-git commented 3 years ago

By the way, if you want a really quick demo of how minimd works, you can install it and use a Markdown file such as this. The main functionality is in these key-bindings and how neatly it does the folding and lets you move around the document. Thanks again for all your help

habamax commented 3 years ago

Is this what you would like to have? image

ossie-git commented 3 years ago

Looks good

habamax commented 3 years ago

Check the latest pls

Use let g:asciidoctor_foldnested = v:false to activate new folding

ossie-git commented 3 years ago

Unfortunately, the behavior is still erratic. To minimize the likelihood of something else being at work, I created a new vimrc file and removed basically everything except for the plugin. So my vimrc file looks like this. The behavior is still the same as before

set nocompatible              " be iMproved, required

let g:asciidoctor_folding = 1
let g:asciidoctor_fenced_languages = ['python', 'c', 'asciidoc', 'vim', 'javascript', 'json']
let g:asciidoctor_foldnested = v:false

call plug#begin('~/.vim/plugged')

Plug 'habamax/vim-asciidoctor'

call plug#end()

filetype off
set tabstop=2
set softtabstop=2

filetype plugin indent on
set omnifunc=syntaxcomplete#Complete
syntax on
habamax commented 3 years ago

and you did update the plugin, right?

habamax commented 3 years ago

BTW, mappings that I have provided earlier would not work for g:asciidoctor_foldnested = v:false.

Now there is only 1 foldlevel that you can zM or zR.

habamax commented 3 years ago

You can play with the following:

func! FoldLevel(count) abort
    if !&foldenable
        return
    endif
    try
        let pos = getcurpos()
        silent! exe "%normal! zc"
        silent! exe 'g/^=\{'..(a:count)..'}\s/normal! zo'
    finally
        call setpos('.', pos)
    endtry
endfunc

nnoremap <silent> <space><tab> :<C-u>call FoldLevel(v:count1)<CR>
ossie-git commented 3 years ago

Ah. I think it might be working now. If you mean that the only options that are available are:

then everything is working (from my limited testing). I thought that it implemented 1<space>, 2<space>, 3<space>, which isn't working

I updated the plugin (PlugUpdate) and verified it by reading the installed .doc file. I also didn't use the old mappings that you had previously shared. I am using only the above configuration file.

habamax commented 3 years ago

I thought that it implemented 1, 2, 3, which isn't working

I believe this should be user config, try 2<space><tab> from the prev post.

habamax commented 3 years ago

Ah. I think it might be working now. If you mean that the only options that are available are:

  • close everything
  • open everything
  • the normal close current fold using <space>

Well, yes, with non-nesting folds there is only 1 level of folding you can toggle for each fold.

ossie-git commented 3 years ago

The new FoldLevel looks like it works but the behavior is kind of strange. When I give it a level, it opens all of the folds at that level and closes all of the ones below it (so you don't even see them in the outline). Is this what you intended? In minimd, when I give it a level, it shows me folds at that level and closes everything below it. So 2<space> would show me all 2L folds (folded) and nothing below. 3<space> would show me all 3L (folded) and nothing below that level. The behavior you implemented is a little different

habamax commented 3 years ago

Do you mean with the mapping I have provided? It is just an example, you should probably play with it to suit what you need.

func! FoldLevel(count) abort
    if !&foldenable
        return
    endif
    try
        let pos = getcurpos()

        " CHANGE HERE
        " close all folds
        silent! exe "%normal! zc"
        " searches for all =, ==, == depending on prefix 1, 2, 3
        " and executes foldopen with       normal! zo
        silent! exe 'g/^=\{'..(a:count)..'}\s/normal! zo'
        " STOP CHANGES

    finally
        call setpos('.', pos)
    endtry
endfunc

nnoremap <silent> <space><tab> :<C-u>call FoldLevel(v:count1)<CR>
habamax commented 3 years ago

So 2<space> would show me all 2L folds (folded) and nothing below. 3<space> would show me all 3L (folded) and nothing below that level. The behavior you implemented is a little different

And this was in the original folding?! Or am I completely miss the point? Cause from your screenshot I have same behavior

habamax commented 3 years ago

So again, this mapping

func! FoldLevel(count) abort
    if !&foldenable
        return
    endif
    try
        let pos = getcurpos()
        silent! exe "%normal! zo"
        silent! exe 'g/^=\{'..a:count..'}\s/normal! zc'
    finally
        call setpos('.', pos)
    endtry
endfunc

nnoremap <silent> <space> :<C-u>call FoldLevel(v:count1)<CR>

n <space> folds all sections of level n leaving every other levels open

Next mapping

func! FoldLevel(count) abort
    if !&foldenable
        return
    endif
    try
        let pos = getcurpos()
        silent! exe 'g/^=\{'..a:count..'}\s/normal! zc'
    finally
        call setpos('.', pos)
    endtry
endfunc

nnoremap <silent> <space> :<C-u>call FoldLevel(v:count1)<CR>

n <space> folds all sections of level n not touching any other folds -- if they are closed, would stay closed and vice versa.

ossie-git commented 3 years ago

Oops. That's not the behavior the minimd gives you. It closes everything as I showed you in the original image when I ran 3<space>. This means can easily see my entire document and zoom in on a specific section and then open only that section or move around sections easily. So minimd will not open any levels for you unless you go to the level and press <space> to open it. This behavior is fantastic for working with outlines and getting various levels of visibility into your document

So it is basically like AsciiDoc's toclevels option that you set with X<space> while it hides all the content

ossie-git commented 3 years ago

Here is a demo of it in action. I just use: <space> to close everything at the beginning and then show using 2<space>, 3<space> and moving around in the document and opening folds. I apologize for any confusion I may have caused

minimd

habamax commented 3 years ago

? vim-asciidoctor-5

habamax commented 3 years ago
func! FoldLevel(count) abort
    if !&foldenable
        return
    endif
    if a:count == 0
        normal! za
    elseif a:count == 1
        %foldclose!
    else
        let &foldlevel = a:count - 1
    endif
endfunc

let g:asciidoctor_foldtitle_as_h1 = 0
nnoremap <space> :<C-u>call FoldLevel(v:count)<CR>

With the latest master and this snippet it should work similar to minimd.

habamax commented 3 years ago

If it would work for you, I will add <plug> mapping you can use instead.