0

I would like to tag lines with a certain text property and then sort all lines with that text property to come to the top. How can I sort based on having a text property rather than a pattern match?

1
  • Did either of the solutions below work for you?
    – B Layer
    Commented Oct 30, 2021 at 21:13

2 Answers 2

3

This solution uses a simple trick; instead of moving lines you care about to the top, move the other lines to the bottom. This preserves order without any extra book-keeping and allows us to use the g/ command which processes lines in order.

function! LineHasProp(line, type) abort
  return !prop_list(a:line)->filter({_, v -> v.type ==# a:type})->empty()
endfunction

:g/^/if !LineHasProp(line('.'), 'type')|m$|end
2

There's nothing like that built in. A custom function would be necessary. An actual general sort would be fairly involved but I can provide you with a function that will do the one specific thing you mention: move all lines with a certain text property to the top of the buffer. (Since "a certain text property" is ambiguous I'm assuming that you mean text properties with a specific type.)

func! TextPropsToTop(type) abort
    let l:cnt = 0  " num lines found with TP of specified type
    1 " cursor to beginning of buffer

    " Search forward from current line
    let l:props = prop_find(#{type: a:type})
    while !empty(l:props)
        " move found line to below the last moved line (maintaining order)
        exe l:props['lnum'] . "move " . l:cnt
        let l:cnt += 1
        " move cursor back to where we found last TP
        exe l:props['lnum']
        " search for the next one
        let l:props = prop_find(#{type: a:type})
    endwhile
endfunc

Call like so :call TextPropsToTop("TpTypeName").

The comments should help explain everything. As they say this maintains the order that the targeted lines have in relation to each other.

It's tested but not what I'd call exhaustively.

Just to compare/contrast to the other answer here...while the other is nice and compact this one doesn't iterate over every line in the file; it processes only lines with the specified TP type. Presumably target lines make up a small percentage of total lines so there's something to be said for this kind of efficiency, especially in large files. (Assuming prop_find() is properly optimized!)

5
  • It is not specified in the question but I suppose using "move" is necessary, since otherwise the text props will not follow the text (if using e.g., setline)
    – Mass
    Commented Oct 10, 2021 at 0:08
  • @Mass Actually, AFAIK, any kind of direct movement of a line loses its text properties. They only stay if the line is moved as a result of other lines being added/deleted. I tried :move, :sort, yank/put, etc...with several versions of Vim...TP is gone in every case. (In the case of your answer that would mean TPs with types other than the target type will be lost.) I'm thinking (hoping?) OP is just using the TP as temporary markers and won't be bothered by this.
    – B Layer
    Commented Oct 10, 2021 at 3:33
  • (Not yank/put but delete/put, I meant.)
    – B Layer
    Commented Oct 10, 2021 at 3:47
  • Oh.. surely that is a bug? Marks definitely move with :move and text props are supposed to be better marks..
    – Mass
    Commented Oct 10, 2021 at 13:13
  • @Mass It surprised me, too, but I tried it on three different platforms with builds new and old. It's hard to believe that if it were a bug it would go unaddressed for so long. (The documentation is not clear as to what to expect.)
    – B Layer
    Commented Oct 11, 2021 at 1:32

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.