You cannot. From :h 'number'
(emphasis mine):
Print the line number in front of each line
You can only enable number
or relativenumber
for the whole window.
See:
:help 'number'
:help 'relativenumber'
Edit:
In Vim, this isn't feasible because 'signcolumn'
has a max width of 2 characters. For some reason, even though Neovim supports larger sign columns, each individual sign text must still be 1 or 2 characters. If this were not the case, it would be possible in Neovim (Relevant source code). This would have to be changed.
This might be easier done in Lua (I don't know, I've never written a Lua plugin for Nvim), but here is a solution in Vimscript. No guarantees about performance or "correctness" (it's kind of just thrown together), but it appears to work, let me know if I've missed some bug:
let g:custom_number_delimiter='##'
let s:sign_id=500 " script level variable of current sign ID
function! s:get_section_lines() abort
" save cursor pos to restore
let l:cursor_pos=[line('.'), col('.')]
" Get line number by:
" 1. :g/re/p for start of sections
" 2. split output of :g/re/p into List
" 3. isolate line numbers from output
let l:section_start_lnums=s:isolate_lnums(split(execute('g/' . g:custom_number_delimiter . '.\+' . g:custom_number_delimiter . '/p#'), "\n"))
" no matches
if len(l:section_start_lnums) == 0
return []
endif
" restore cursor pos (:g/re/p moves to last match, be nice and put it back)
call cursor(cursor_pos)
" build list of ranges in the format [[range_start_line, range_end_line], ...]
let l:prev_lnum=-1
let l:curr_lnum=-1
let l:sections=[]
for lnum in l:section_start_lnums
let l:prev_lnum=l:curr_lnum
let l:curr_lnum=lnum
if l:prev_lnum != -1
call add(l:sections, [l:prev_lnum, l:curr_lnum-1])
endif
endfor
" logically, final section extends to end of file
call add(l:sections, [l:curr_lnum, line('$')])
return l:sections
endfunction
" gradually trim line until only the line number remains
function! s:isolate_lnums(section_lines) abort
if a:section_lines[0] =~ "Pattern not found"
return []
endif
let l:lnums=[]
for section_line in a:section_lines
" trim trailing characters
let l:lnum = substitute(section_line, '^\s\+\d\+\zs.*', '', '')
" trim excess whitespace
let l:lnum = substitute(l:lnum, '\s', '', 'g')
call add(l:lnums, str2nr(l:lnum))
endfor
return l:lnums
endfunction
" define more signs, if needed
" note: doesn't abort on error
function! s:define_signs(sections)
let l:biggest_diff=-1
for section in a:sections
let l:curr_diff=section[1]-section[0]
let l:biggest_diff=l:curr_diff > l:biggest_diff ? l:curr_diff : l:biggest_diff
endfor
for i in range(l:biggest_diff+1)
" fail silently when lnum is >= 100 in Vim
" In NeoVim use :h 'signcolumn' and :h 'number' accordingly
exec 'silent! sign define Lnum' . i . ' texthl=LineNr text=' . i
endfor
endfunction
" place signs in buffer
" note: doesn't abort on error
function! s:place_signs(sections)
" clear all of our signs for current buffer
exec 'sign unplace * group=CustomNumber buffer=' . bufnr()
" no matches
if len(a:sections) == 0
return
endif
" define signs, if needed
call s:define_signs(a:sections)
for section in a:sections
let l:custom_lnum=0
for lnum in range(section[0], section[1])
exec 'silent! sign place ' . s:sign_id . ' line=' . lnum . ' name=Lnum' . l:custom_lnum . ' group=CustomNumber buffer=' . bufnr()
let l:custom_lnum+=1
let s:sign_id+=1
endfor
endfor
endfunction
augroup CustomNumber
autocmd!
autocmd BufEnter,BufNew,TextChanged,TextChangedI,TextChangedP * call s:place_signs(s:get_section_lines())
augroup END
And here is what that looks like in Vim:
See:
:h 'signcolumn'
:h :sign
:h :sign-define
:h :sign-place
:h :sign-unplace