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?
2 Answers
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
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!)
-
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)– MassCommented 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 LayerCommented Oct 10, 2021 at 3:33 -
-
Oh.. surely that is a bug? Marks definitely move with
:move
and text props are supposed to be better marks..– MassCommented 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 LayerCommented Oct 11, 2021 at 1:32