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

Include text object for fenced code block? #282

Open
schoettl opened this issue Jun 26, 2016 · 8 comments
Open

Include text object for fenced code block? #282

schoettl opened this issue Jun 26, 2016 · 8 comments

Comments

@schoettl
Copy link

Hi,

I have written text objects for fenced code blocks.

E.g. cif replaces the code inside, daf deletes a code block with fence markers, or vif visually selects code inside so it can be pasted (middle mouse click) to an interpreter.

Do you consider this a good feature? Would you accept an pull request?

Thanks, Jakob

@Gullumluvl
Copy link

Very interesting, I concur too! Why not extend the text object to any code block (default markdown indented ones too)? Would love to use that in combination with a plugin like Slimux!

@lfilho
Copy link

lfilho commented Jul 29, 2019

I was looking for that! @schoettl can you share what you've done?

@pyrho
Copy link

pyrho commented Sep 4, 2020

Here is my attempt at creating text objects for fenced code blocks. It is severly untested so YMMV (:

function! s:inCodeFence()
    " Search backwards for the opening of the code fence.
	call search('^```.*$', 'bceW')
    " Move one line down
	normal! j
    " Move to the begining of the line at start selecting
	normal! 0v
    " Search forward for the closing of the code fence.
	call search("```", 'ceW')

	normal! kg_
endfunction

function! s:aroundCodeFence()
    " Search backwards for the opening of the code fence.
	call search('^```.*$', 'bcW')
	normal! v$
    " Search forward for the closing of the code fence.
	call search('```', 'eW')
endfunction

autocmd Filetype markdown xnoremap <silent> if :<c-u>call <sid>inCodeFence()<cr>
autocmd Filetype markdown onoremap <silent> if :<c-u>call <sid>inCodeFence()<cr>
autocmd Filetype markdown xnoremap <silent> af :<c-u>call <sid>aroundCodeFence()<cr>
autocmd Filetype markdown onoremap <silent> af :<c-u>call <sid>aroundCodeFence()<cr>

@schoettl
Copy link
Author

schoettl commented Sep 5, 2020

Sorry for the late answer, I'll also share my solution: Put a file markdown.vim into ~/.vim/ftplugin/ with this content:

function! s:SelectFencedCodeA()
    execute "normal! $?^````*$\<CR>V/^````*$\<CR>o"
endfunction

function! s:SelectFencedCodeI()
    call <SID>SelectFencedCodeA()
    normal! joko
endfunction

nmap     <buffer>         va`      :call <SID>SelectFencedCodeA()<CR>
nmap     <buffer>         vi`      :call <SID>SelectFencedCodeI()<CR>
onoremap <buffer><silent> a`       :call <SID>SelectFencedCodeA()<CR>
onoremap <buffer><silent> i`       :call <SID>SelectFencedCodeI()<CR>

" Good default for Markdown:
set textwidth=80

@pyrho I'm not sure but I think, your solution registers the key mapping in every buffer. That's why I use <buffer>.

PS: My current solution only works for "plain" fenced code without a language. You will have to change the first backward search regex (after ?) to also match a language name.

@pyrho
Copy link

pyrho commented Sep 10, 2020

@schoettl Thanks for sharing.
Indeed Creating the mappings via ftplugin/markdown.vim is better than my autocmd on FileType (after/ftplugin/ maybe even better suited for user-defined mappings).

your solution registers the key mapping in every buffer.

I think you are right, <buffer> is better (vimways confirms this ^^ I didn't know about <buffer>)

@jdhao
Copy link

jdhao commented Nov 12, 2020

@pyrho @schoettl IIRIC, markdown code blocks can have indented spaces before them. So the code block does not necessarily need to begin with backticks. It may well begin with white spaces. You may add \s* before your pattern.

@schoettl I think we should use three backticks instead of four. Also setting code blocks text objects to i` and a` will shadow the text objects for inline markdown code. Maybe it should be better avoided.

This is my attempt to provide a text object for code blocks:

vnoremap <silent> ic :<C-U>call <SID>MdCodeBlockTextObj('i')<CR>
onoremap <silent> ic :<C-U>call <SID>MdCodeBlockTextObj('i')<CR>

vnoremap <silent> ac :<C-U>call <SID>MdCodeBlockTextObj('a')<CR>
onoremap <silent> ac :<C-U>call <SID>MdCodeBlockTextObj('a')<CR>

function! s:MdCodeBlockTextObj(type) abort
  " the parameter type specify whether it is inner text objects or arround
  " text objects.
  let start_row = searchpos('\s*```', 'bn')[0]
  let end_row = searchpos('\s*```', 'n')[0]

  let buf_num = bufnr()
  if a:type ==# 'i'
    let start_row += 1
    let end_row -= 1
  endif
  " echo a:type start_row end_row

  call setpos("'<", [buf_num, start_row, 1, 0])
  call setpos("'>", [buf_num, end_row, 1, 0])
  execute 'normal! `<V`>'
endfunction

@schoettl
Copy link
Author

schoettl commented Nov 12, 2020

Hi @jdhao

@schoettl I think we should use three backticks instead of four.

My code allows three or more backticks. Actually, it's even more special: the fence must not be indented more than three spaces ^^

Also setting code blocks text objects to i` and a` will shadow the text objects for inline markdown code. Maybe it should be better avoided.

Do you know which plugin is it, that already provides the inline code text objects? Or is it built-in in markdown.vim?

@jdhao
Copy link

jdhao commented Nov 13, 2020

@schoettl The i` and a` objects are builtin at least in Neovim, as can be verified by using nvim -u NORC test.md and use these two objects. There is also help tag for them: see :h i` and :h a` .

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

No branches or pull requests

5 participants