модификация функции vim постоянно дает мне: «Недостаточно аргументов для функции» - PullRequest
0 голосов
/ 21 апреля 2011

У меня есть эта функция:

function! Find(name)
  let l:list=system("find . -name '".a:name."' | perl -ne 'print \"$.\\t$_\"'")
  let l:num=strlen(substitute(l:list, "[^\n]", "", "g"))
  if l:num < 1
    echo "'".a:name."' not found"
    return
  endif
  if l:num != 1
    echo l:list
    let l:input=input("Which ? (CR=nothing)\n")
    if strlen(l:input)==0
      return
    endif
    if strlen(substitute(l:input, "[0-9]", "", "g"))>0
      echo "Not a number"
      return
    endif
    if l:input<1 || l:input>l:num
      echo "Out of range"
      return
    endif
    let l:line=matchstr("\n".l:list, "\n".l:input."\t[^\n]*")
  else
    let l:line=l:list
  endif
  let l:line=substitute(l:line, "^[^\t]*\t./", "", "")
  execute ":e ".l:line
endfunction
command! -nargs=1 Find :call Find("<args>")

Когда я пытаюсь добавить параметр, чтобы объявление стало function! Find(name, search_dir), оно всегда говорит мне, что у меня недостаточно параметров, когда я вызываю функцию в vim, используя :Find x y (где Find: x будет работать, когда в объявлении функции был только 1 параметр.

Есть идеи, как добавить несколько параметров?

Конечная цель состоит в том, чтобы иметь функцию Find, которая находит в указанном подкаталоге.

Ответы [ 2 ]

1 голос
/ 21 апреля 2011

Дополнение к ответу @Peter Rincker: никогда не следует использовать "<args>", если вы хотите передать параметр в функцию, поскольку уже есть встроенные <q-args> и <f-args>, которые не нуждаются в дополнительном цитировании и не вводят возможность внедрения кода (попробуйте Find ".string(g:)." с вашим кодом). Первый передаст все параметры как один элемент, второй выдаст список параметров, подходящих для вызова функции:

command -nargs=+ Find :call Find(<f-args>)

Что еще нужно учесть:

  1. (системный вызов) Никогда не передавайте пользовательский ввод в оболочку как есть, используйте shellescape(str, 1). Здесь могут возникнуть непредвиденные проблемы.
  2. strlen(substitute(l:input, "[0-9]", "", "g"))>0 условие эквивалентно input=~#'\D', но намного больше.
  3. Вам не нужно указывать l:: это область действия по умолчанию внутри функций.
  4. Имеется встроенная функция glob(): всю строку system() можно заменить на

    join(map(split(glob('./*'.escape(a:name, '\`*[]?').'*'), "\n"), 'v:key."\t".v:val'), "\n")
    
  5. Не забывайте избегать всего, что вы выполняете: execute ":e ".l:line должно быть записано как execute "e" fnameescape(line) (это третье место, где внедрение кода возможно в таком простом фрагменте кода!).
  6. Лучше использовать списки здесь, в этом случае вам не нужно использовать что-то для добавления номеров строк:

    function s:Find(name)
        let list=split(glob('./*'.fnameescape(a:name).'*'), "\n")
        if empty(list)
            echo string(a:name) "not found"
            return
        endif
        let num=len(list)
        if num>1
            echo map(copy(list), 'v:key."\t".v:val')
            let input=input("Which?")
            if empty(input)
                return
            elseif input=~#'\D'
                echo "Not a number"
                return
            elseif input<1 || input>num
                echo "Out of range"
                return
            endif
            let line=list[input]
         else
            let line=list[0]
         endif
         execute "e" fnameescape(line)
     endfunction
     command! -nargs=1 Find :call Find(<f-args)
    
  7. Ни вы, ни я не справляемся с ситуацией, когда имя файла, которое соответствует шаблону, содержит новую строку. Я знаю, как справиться с этим (вы можете увидеть мой vim-fileutils плагин (устарел) или os.listdir функция os модуль frawor * Плагин 1044 * (на стадии альфа, не размещен на vim.org). Я не думаю, что такая ситуация вероятна, поэтому просто помните, что это возможно.
1 голос
/ 21 апреля 2011

Вам нужно изменить -nargs=1 на -nargs=+.Это будет означать, что вы должны иметь аргументы, но не указывать число.Я предлагаю вам изменить Find функцию на Find(...) и использовать a:0, чтобы получить количество аргументов для ошибки, если используется недопустимое количество аргументов.

Пример функции и команды с несколькими параметрами:

command! -nargs=+ -complete=dir Find call Find(<f-args>)
fun! Find(name, ...)
  let dir = getcwd()
  if a:0 == 1
    let dir = getcwd() . '/' . (a:1 =~ '[/\\]$' ? a:1 : a:1 . '/')
  elseif a:0 != 0
    echohl ErrorMsg
    echo "Must supply 1 or 2 arguments"
    echohl NONE
  endif
  let &efm = "%f"
  cexpr []
  caddexpr split(glob(dir . '**/*' . escape(a:name, '\`*[]?') . '*'), '\n')
  copen
  aug Find
    au!
    au BufLeave <buffer> ccl|aug! Find
  aug END
endfun

Для получения дополнительной помощи

:h :command-nargs
:h ...

Редактировать Добавлен пример функции, которая использует несколько параметров, как предложено @ ZyX.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...