1. function! PyDocstrTxtObj (inner)
  2.     " TEXT OBJECT FOR IN/AROUND PYTHON DOCSTRING
  3.     "
  4.     " For docstrings in this format:
  5.     " ,------------------------------.
  6.     " | '''                          |
  7.     " | Module-level docstring.      |
  8.     " | Text object works on these.  |
  9.     " | '''                          |
  10.     " |                              |
  11.     " | class Widget (object):       |
  12.     " | '''                          |
  13.     " | Text object also works       |
  14.     " | on class-level docstrings.   |
  15.     " | '''                          |
  16.     " |     def __init__ (self):     |
  17.     " |         '''                  |
  18.     " |         Method-level, too!   |
  19.     " |         '''                  |
  20.     " |         pass                 |
  21.     " |                              |
  22.     " '------------------------------'
  23.     " Text objects search up, but won't cross def/class lines.
  24.     "
  25.     " get current line number
  26.     let s = line('.')
  27.     " climb up to first def/class line, or first line of buffer
  28.     while s > 0 && getline(s) !~ '^\s*\(def\|class\)'
  29.         let s = s - 1
  30.     endwhile
  31.     " set search start to just after def/class line, or on first buffer line
  32.     let s = s + 1
  33.     " descend lines until end of buffer or def/class line
  34.     while s < line('$') && getline(s) !~ '^\s*\(def\|class\)'
  35.         " if line begins with optional whitespace followed by '''
  36.         if getline(s) =~ "^\\s*'''"
  37.             " set search end to just after found start line
  38.             let e = s + 1
  39.             " descend lines until end of buffer or def/class line
  40.             while e <= line('$') && getline(e) !~ '^\s*\(def\|class\)'
  41.                 " if line ends with ''' followed by optional whitespace
  42.                 if getline(e) =~ "'''\\s*$"
  43.                     " TODO check first for blank lines above to select instead
  44.                     " for 'around', extend search end through blank lines
  45.                     if !a:inner
  46.                         let x = e + 1
  47.                         while x <= line('$') && getline(x) =~ '^\s*$'
  48.                             let e = x
  49.                             let x = x + 1
  50.                         endwhile
  51.                     endif
  52.                     " visual line select from start to end (first cursor move)
  53.                     exe 'norm '.s.'ggV'.e.'gg'
  54.                     return
  55.                 endif
  56.                 " move search end down a line
  57.                 let e = e + 1
  58.             endwhile
  59.         endif
  60.         " move search start down a line
  61.         let s = s + 1
  62.     endwhile
  63. endfunction
  64.  
  65. " map in/around python docstring text objects
  66. onoremap <silent>ad :<C-u>cal PyDocstrTxtObj(0)<CR>
  67. onoremap <silent>id :<C-u>cal PyDocstrTxtObj(1)<CR>
  68. vnoremap <silent>ad :<C-u>cal PyDocstrTxtObj(0)<CR>
  69. vnoremap <silent>id :<C-u>cal PyDocstrTxtObj(1)<CR>
  70.  
  71. " This code is released under WTFPL Version 2 (http://www.wtfpl.net/)