Я могу получить позицию курсора с помощью getpos()
, но я хочу получить выделенный текст внутри строки, то есть '<,'>
. Как это сделано?
UPDATE
Я думаю, что отредактировал ту часть, где я объяснил, что хочу получить этот текст от Vim script...
Я могу получить позицию курсора с помощью getpos()
, но я хочу получить выделенный текст внутри строки, то есть '<,'>
. Как это сделано?
UPDATE
Я думаю, что отредактировал ту часть, где я объяснил, что хочу получить этот текст от Vim script...
Я не совсем уверен в контексте здесь, потому что getpos()
действительно может принимать отметки (например, '<
и '>
) в качестве аргументов.
Однако, чтобы взять удар по тому, что вы можете просить, там также v
, который похож на '<
, за исключением того, что он всегда обновляется (т.е. пока пользователь все еще находится в визуальном режиме). Это можно использовать в комбинации с .
, текущей позицией курсора, которая затем будет представлять конец визуального выделения.
Изменить: я нашел их в :help line()
; несколько функций, включая line()
и getpos()
, имеют один и тот же набор возможных аргументов.
Изменить: я думаю, вы, вероятно, просто спрашиваете, как получить текст между двумя произвольными отметками, а не по очереди... (т.е. это не относится к визуальному режиму). Я не думаю, что на самом деле есть способ. Да, это похоже на довольно вопиющее упущение. Вы должны подделать его, найдя метки с getpos()
, получив все строки с помощью getline()
, а затем отрубив первый и последний в соответствии с положением столбца (с работой в зависимости от того, много ли он или нет)). Извините, это не настоящий ответ, но, по крайней мере, вы можете обернуть его функцией и забыть об этом.
Я пришел сюда, задав тот же вопрос, что и стартер темы, и попробовал код Люка Хермита, но это не сработало для меня (когда визуальный выбор по-прежнему действует, пока мой код выполняется), поэтому я написал функцию ниже, который, похоже, работает нормально:
function! s:get_visual_selection()
let [line_start, column_start] = getpos("'<")[1:2]
let [line_end, column_end] = getpos("'>")[1:2]
let lines = getline(line_start, line_end)
if len(lines) == 0
return ''
endif
let lines[-1] = lines[-1][: column_end - 2]
let lines[0] = lines[0][column_start - 1:]
return join(lines, "\n")
endfunction
Я надеюсь, что это кому-то полезно!
Обновление (май 2013 г.): На самом деле это еще не совсем корректно, я недавно исправил следующую ошибку в одном из подключаемых модулей Vim, которые я опубликовал:
function! s:get_visual_selection()
" Why is this not a built-in Vim script function?!
let [line_start, column_start] = getpos("'<")[1:2]
let [line_end, column_end] = getpos("'>")[1:2]
let lines = getline(line_start, line_end)
if len(lines) == 0
return ''
endif
let lines[-1] = lines[-1][: column_end - (&selection == 'inclusive' ? 1 : 2)]
let lines[0] = lines[0][column_start - 1:]
return join(lines, "\n")
endfunction
Обновление (май 2014 г.): Этот (тривиальный) код лицензируется как общедоступный. Сделайте с этим то, что вы хотите. Кредиты приветствуются, но не требуются.
Лучший способ, который я нашел, - вставить выделение в регистр:
function! lh#visual#selection()
try
let a_save = @a
normal! gv"ay
return @a
finally
let @a = a_save
endtry
endfunction
В Linux существует дешевая, но эффективная альтернатива программированию такой функции GetVisualSelection()
: используйте регистр *
!
Регистр *
содержит содержимое самого последнего выбора Visual. См. :h x11-selection
.
В script вы можете просто получить доступ к @*
, чтобы получить визуальный выбор.
let v = @*
Кстати, *
также является аккуратным помощником в интерактивном использовании. Например, в режиме вставки вы можете использовать CTRL-R *
, чтобы вставить то, что вы выбрали ранее. Нет явного участия.
Это работает только в операционных системах, поддерживающих механизм выбора X11.
Я однажды написал функцию, которая может это сделать, не касаясь регистров или позиции курсора:
function s:F.map.getvrange(start, end)
let [sline, scol]=a:start
let [eline, ecol]=a:end
let text=[]
let ellcol=col([eline, '$'])
let slinestr=getline(sline)
if sline==eline
if ecol>=ellcol
call extend(text, [slinestr[(scol-1):], ""])
else
call add(text, slinestr[(scol-1):(ecol-1)])
endif
else
call add(text, slinestr[(scol-1):])
let elinestr=getline(eline)
if (eline-sline)>1
call extend(text, getline(sline+1, eline-1))
endif
if ecol<ellcol
call add(text, elinestr[:(ecol-1)])
else
call extend(text, [elinestr, ""])
endif
endif
return text
endfunction
Он вызывается так:
let [sline, scol, soff]=getpos("'<")[1:]
let [eline, ecol, eoff]=getpos("'>")[1:]
if sline>eline || (sline==eline && scol>ecol)
let [sline, scol, eline, ecol]=[eline, ecol, sline, scol]
endif
let lchar=len(matchstr(getline(eline), '\%'.ecol.'c.'))
if lchar>1
let ecol+=lchar-1
endif
let text=s:F.map.getvrange([sline, scol], [eline, ecol])
Обратите внимание, что на этом этапе у вас будет список строк в тексте: одна из причин, почему я написал эту функцию, - это способность хранить NULL в файле. Если вы придерживаетесь любого решения, которое хранит текст в регистре, все NULL будут заменены символами новой строки, и все символы новой строки будут представлены как символы новой строки. В выходном сигнале функции getvrange, хотя NULL представлены как символы новой строки, в то время как символы новой строки представлены разными элементами: между каждым элементом списка имеется NL, как и на выходе getline(start, end)
.
Эта функция может использоваться только для получения строк для выбора символа (как для linseise, это намного проще и для blockwise я перебираю по строкам и не нуждаюсь в такой функции). Существуют также функции для удаления заданного диапазона (без касания регистров) и вставка текста в заданное положение (без касания регистров или курсора).
Это довольно старый вопрос, но поскольку я могу представить, что в какой-то момент на него наткнется много людей, здесь моя измененная версия ответа @xolox
function! VisualSelection()
if mode()=="v"
let [line_start, column_start] = getpos("v")[1:2]
let [line_end, column_end] = getpos(".")[1:2]
else
let [line_start, column_start] = getpos("'<")[1:2]
let [line_end, column_end] = getpos("'>")[1:2]
end
if (line2byte(line_start)+column_start) > (line2byte(line_end)+column_end)
let [line_start, column_start, line_end, column_end] =
\ [line_end, column_end, line_start, column_start]
end
let lines = getline(line_start, line_end)
if len(lines) == 0
return ''
endif
let lines[-1] = lines[-1][: column_end - 1]
let lines[0] = lines[0][column_start - 1:]
return join(lines, "\n")
endfunction
'<
и '>
не обновляются, когда пользователь все еще находится в визуальном режиме, поэтому в этом случае необходимо использовать .
и v
.'>
перед текстом '<
. В этих случаях две позиции просто необходимо обратить вспять.Предполагая, что переменная "reverse" определяется, когда метки находятся в обратном порядке:
if exists("reverse")
let lines_r = []
for line in lines
call insert(lines_r, join(reverse(split(line, ".\\zs"))))
endfor
return join(lines_r, "\n")
else
return join(lines, "\n")
end
Я думаю, вы должны использовать "resgisiter" для буфера обмена.
Для более подробной информации вы можете прочитать справку: h clipboard-autoselect '
Если вы включите эту опцию (установите буфер = неназванный, автоматический выбор),
вы можете легко выбрать выделенный текст
"пусть l: text = @*"
Эта функция, взятая из vim-asterisk, также работает в отображениях <expr>
, поддерживает выборку блоков и многобайтовые столбцы.
function! GetVisualSelection()
let mode = mode()
let end_col = s:curswant() is s:INT.MAX ? s:INT.MAX : s:get_col_in_visual('.')
let current_pos = [line('.'), end_col]
let other_end_pos = [line('v'), s:get_col_in_visual('v')]
let [begin, end] = s:sort_pos([current_pos, other_end_pos])
if s:is_exclusive() && begin[1] !=# end[1]
" Decrement column number for :set selection=exclusive
let end[1] -= 1
endif
if mode !=# 'V' && begin ==# end
let lines = [s:get_pos_char(begin)]
elseif mode ==# "\<C-v>"
let [min_c, max_c] = s:sort_num([begin[1], end[1]])
let lines = map(range(begin[0], end[0]), '
\ getline(v:val)[min_c - 1 : max_c - 1]
\ ')
elseif mode ==# 'V'
let lines = getline(begin[0], end[0])
else
if begin[0] ==# end[0]
let lines = [getline(begin[0])[begin[1]-1 : end[1]-1]]
else
let lines = [getline(begin[0])[begin[1]-1 :]]
\ + (end[0] - begin[0] < 2 ? [] : getline(begin[0]+1, end[0]-1))
\ + [getline(end[0])[: end[1]-1]]
endif
endif
return join(lines, "\n") . (mode ==# 'V' ? "\n" : '')
endfunction
let s:INT = { 'MAX': 2147483647 }
" @return Number: return multibyte aware column number in Visual mode to select
function! s:get_col_in_visual(pos) abort
let [pos, other] = [a:pos, a:pos is# '.' ? 'v' : '.']
let c = col(pos)
let d = s:compare_pos(s:getcoord(pos), s:getcoord(other)) > 0
\ ? len(s:get_pos_char([line(pos), c - (s:is_exclusive() ? 1 : 0)])) - 1
\ : 0
return c + d
endfunction
function! s:get_multi_col(pos) abort
let c = col(a:pos)
return c + len(s:get_pos_char([line(a:pos), c])) - 1
endfunction
" Helper:
function! s:is_visual(mode) abort
return a:mode =~# "[vV\<C-v>]"
endfunction
" @return Boolean
function! s:is_exclusive() abort
return &selection is# 'exclusive'
endfunction
function! s:curswant() abort
return winsaveview().curswant
endfunction
" @return coordinate: [Number, Number]
function! s:getcoord(expr) abort
return getpos(a:expr)[1:2]
endfunction
"" Return character at given position with multibyte handling
" @arg [Number, Number] as coordinate or expression for position :h line()
" @return String
function! s:get_pos_char(...) abort
let pos = get(a:, 1, '.')
let [line, col] = type(pos) is# type('') ? s:getcoord(pos) : pos
return matchstr(getline(line), '.', col - 1)
endfunction
" @return int index of cursor in cword
function! s:get_pos_in_cword(cword, ...) abort
return (s:is_visual(get(a:, 1, mode(1))) || s:get_pos_char() !~# '\k') ? 0
\ : s:count_char(searchpos(a:cword, 'bcn')[1], s:get_multi_col('.'))
endfunction
" multibyte aware
function! s:count_char(from, to) abort
let chars = getline('.')[a:from-1:a:to-1]
return len(split(chars, '\zs')) - 1
endfunction
" 7.4.341
" http://ftp.vim.org/vim/patches/7.4/7.4.341
if v:version > 704 || v:version == 704 && has('patch341')
function! s:sort_num(xs) abort
return sort(a:xs, 'n')
endfunction
else
function! s:_sort_num_func(x, y) abort
return a:x - a:y
endfunction
function! s:sort_num(xs) abort
return sort(a:xs, 's:_sort_num_func')
endfunction
endif
function! s:sort_pos(pos_list) abort
" pos_list: [ [x1, y1], [x2, y2] ]
return sort(a:pos_list, 's:compare_pos')
endfunction
function! s:compare_pos(x, y) abort
return max([-1, min([1,(a:x[0] == a:y[0]) ? a:x[1] - a:y[1] : a:x[0] - a:y[0]])])
endfunction
Обзор:
визуально выбрать, нажать отображение, повторно выбрать исходный выбор с помощью gv и скопировать его в регистр, окончательно вставить из регистра
Случай использования:
функция! Диапазон испытаний()
exe 'sp temp.tmp'
exe 'norm p'
EndFunction