Làm cách nào để làm cho vim tìm trong một tập hợp các thư mục cho một tệp, nếu nó không tồn tại trong thư mục hiện tại?


9

Khi tôi muốn chỉnh sửa zshrc, tôi chỉ cần gõ:

vim .zshrc

Không chỉ định đường dẫn đầy đủ ( ~/.zshrc), nếu tôi ở một thư mục khác, thay vào đó, nó sẽ bắt đầu một tệp mới. Điều này rất khó chịu, vì tôi chỉ có một .zshrc, trong ~và chỉ một vimrc, trong ~/.vim/. Vì vậy, làm thế nào để tôi có được vim để mở ~/.zshrchoặc ~/.vim/vimrckhi tôi làm vim .zshrchoặc vim vimrctrong một thư mục khác?


Trong khi tạo một số cấu hình cho mỗi tệp riêng lẻ là một cách, tôi đã nghĩ về một cái gì đó dọc theo dòng CDPATH. CDPATHlà một biến trong một số shell chứa danh sách các đường dẫn cdsẽ tìm thư mục. Ví dụ: nếu tôi có CDPATH=:/home/muruvà tôi ở trong bất kỳ thư mục nào không chứa thư mục có tên Desktop, tôi có thể làm cd Desktopvà tiếp cận /home/muru/Desktop. Đơn giản, thanh lịch, linh hoạt. Nếu vimcó một VIMPATHnơi mà nó sẽ tìm các tập tin để chỉnh sửa, đó sẽ là lựa chọn tốt nhất.

Câu trả lời:


6

'path'Tùy chọn của Vim cho phép bạn chỉ định các thư mục lệnh nào sẽ thích gf:findsẽ tìm kiếm tệp.

Nếu bạn chỉ muốn chức năng này kích hoạt một tập hợp tệp cụ thể, thì bạn có thể sử dụng autocmd để tự động "chuyển hướng" :editlệnh của bạn đến tệp trong một trong các 'path'thư mục.

set path+=~/
function! FindInPath(name)
    let found = findfile(a:name)
    if !empty(found)
        exe 'silent keepalt file '. fnameescape(found)
        edit
    endif
endfunction
autocmd BufNewFile .vimrc,.zshrc nested call FindInPath(expand('<afile>'))

Điều này sử dụng BufNewFileautocmd như một kích hoạt cho file not found, so try to find it somewhere else. Khi tình huống đó được phát hiện, sử dụng findfile()để cố gắng tìm tệp trong 'path'thư mục. Nếu nó được tìm thấy, thay đổi tên của bộ đệm hiện tại thành tập tin đó và chỉnh sửa lại bộ đệm, nếu không thì tiếp tục sử dụng bộ đệm mới.

Vòng nestedloại được yêu cầu ở đây vì autocmds thường không làm tổ. Trong trường hợp này, bạn không muốn các autocmds điển hình kích hoạt khi :editlệnh mở tệp của bạn.

Lưu ý rằng điều này vẫn sẽ tạo ra một bộ đệm bổ sung so với việc chỉ chỉnh sửa tệp theo cách thủ công. Khi thời gian BufNewFileđược chạy, bộ đệm cho tên tệp được chỉ định ban đầu đã được tạo. Sử dụng :fileđể thay đổi tên của bộ đệm sẽ tạo ra bộ đệm mới, không tải với tên gốc.

Nếu bạn luôn muốn tìm kiếm 'path', thì autocmd có thể được thay đổi để sử dụng *mẫu tệp thay vì chỉ định một số tệp nhất định.


Đây là phiên bản cập nhật phù hợp với yêu cầu của bạn hơn. Nó sử dụng :findđể trực tiếp mở tệp thay vì đặt tên bộ đệm dựa trên kết quả của findfile().

function! FindInPath(name)
    let path=&path
    " Add any extra directories to the normal search path
    set path+=~,~/.vim,/etc
    " If :find finds a file, then wipeout the buffer that was created for the "new" file
    setlocal bufhidden=wipe
    exe 'silent! keepalt find '. fnameescape(a:name)
    " Restore 'path' and 'bufhidden' to their normal values
    let &path=path
    set bufhidden<
endfunction
autocmd BufNewFile * nested call FindInPath(expand('<afile>'))

Điều này giải quyết vấn đề trong chức năng trước đó, nơi Vim sẽ phàn nàn khi cố gắng lưu :filebộ đệm có tên.


Hừm. keepalt filecó nhược điểm giống như gán cho vim.current.buffer.name- vim cảnh báo bạn rằng tệp đã tồn tại khi cố gắng lưu các thay đổi của bạn.
muru

Sau khi sử dụng điều này trong gần một năm, tôi có một số gợi ý: bọc nó lại if expand('%') !~ '^[.~]\?/'... endifđể các đường dẫn tương đối hoặc tuyệt đối được chỉ định rõ ràng bị bỏ qua; và sử dụng silentthay vì silent!, bởi vì nếu bạn mở vim vimrctrong hai thiết bị đầu cuối, thì thiết bị thứ hai sẽ chờ nhập vào cảnh báo "tệp đang mở ở nơi khác" thông thường, nhưng người dùng không biết nó đang chờ đợi điều gì. Tôi chưa chỉnh sửa nó, để xem liệu bạn có cách nào tốt hơn để giải quyết không.
muru

3

Thay thế là để thực hiện một số lệnh sẽ làm điều này dễ dàng hơn:

command! Evimrc e ~/.vimrc
command! Svimrc sp ~/.vimrc

Tôi đang sử dụng E/ Smẫu mà rails.vim / projectionist.vim sử dụng.

Để được trợ giúp thêm xem:

:h :command
:h :e
:h :sp

3

Đây không phải là một giải pháp, nhưng đó là những gì tôi làm để có thể dễ dàng truy cập .vimrc.zshrc. Cá nhân tôi nghĩ rằng điều này là khá gọn gàng:

map <leader>ev :e ~/.vim/vimrc<cr>
map <leader>ez :e ~/.zshrc<cr>

1

Theo tinh thần CDPATH, tôi đã viết một hàm dựa trên Python để làm điều này (với sự giúp đỡ từ Matt Boehm ):

function LookupFiles ()
    python <<EOF
from os.path import *
from vim import *
current_file = eval ('expand("%")')
current_index = str (current.buffer.number)
PATHS = ['~', '~/.vim', '/etc']

if current_file != '' and  not isfile (current_file):
    for p in map (expanduser, PATHS):
        f = join (p, current_file)
        if isfile (f):          
            command ('bad ' + f)
            command ('bd ' + current_index)
            break
EOF
endfunction

autocmd BufWinEnter * nested call LookupFiles() 
  • Tôi đã sử dụng BufWinEnterthay BufNewFilevì bởi vì cái sau dường như không hành xử đáng tin cậy khi nhiều tên tệp như vậy được đưa ra.
  • Sau một chút thử nghiệm và lỗi, tôi đã giải quyết badtheo sau bdnhư một cách đáng tin cậy để đóng bộ đệm đã mở cho tệp không sử dụng. Điều này vẫn không hoạt động khi tôi làm :tabe some-file(không có tab mới nào được mở). Tuy nhiên, đó là một câu hỏi cho một ngày khác.
  • Giống như với CDPATH, tôi có thể dễ dàng thêm nhiều thư mục bằng cách chỉnh sửa PATHShoặc biến nó thành biến cấp Vim và sửa đổi nó.

Điều mà các câu trả lời khác bỏ lỡ, IMO, là tôi không muốn tạo cấu hình cho mỗi tệp , nhưng cho mỗi thư mục . Tôi không quan tâm liệu tôi đang mở fstabhay vimrc, tôi chỉ muốn Vim tìm kiếm tệp trong một số bộ thư mục nếu nó không tồn tại trong thư mục hiện tại. +1 cho tất cả chúng cho những nỗ lực cụ thể tập tin, mặc dù.


Chỉ cần thay đổi câu trả lời của tôi để sử dụng *cho mẫu tệp, thay vì các tệp cụ thể, sẽ đạt được điều tương tự và tránh vấn đề của bạn :tabe.
jamessan

@jamessan Tôi thừa nhận tôi đã thấy autocmd ban đầu và khoanh vùng. Trên một lưu ý không liên quan: fnameescape có thể là giải pháp cho một câu hỏi khác ở đây, về gvim và gửi từ xa.
muru

1

Với 'user-commands''Dictionary', chúng ta có thể chỉnh sửa các tệp mà không cần tạo bộ đệm để ghi đè tệp mà chúng ta muốn chỉnh sửa trên bộ đệm.

com -nargs=* E call Editfile(<q-args>)
let s:fileLocation = {'vimrc':'~/.vim/', '.zshrc':'~/'}
function Editfile(filename)
    if has_key(s:fileLocation, a:filename)
        exe "e " . fnameescape(s:fileLocation[a:filename].a:filename)
    else
        exe "e " . fnameescape(a:filename)
    endif
endfunction 

Lưu ý rằng hàm Editfilekhông cố gắng xác minh đối số của nó. Hãy để vim xử lý tất cả các lỗi như các lệnh Ex thông thường khác. Nếu đối số là đúng thì vim bắt đầu chỉnh sửa tệp và nếu không đúng thì vim sẽ báo lỗi.

Theo tôi, chúng ta không cần phải tạo bộ đệm. Nó có hai nhược điểm chính.

  1. Các 'not-edited'lá cờ sẽ được thiết lập. Như jamessan chỉ ra trong câu trả lời của anh ấy , nếu chúng tôi đặt tên tệp hiện tại bằng :filelệnh và cố gắng ghi tệp, chúng tôi sẽ gặp thông báo lỗi E13: File exists (use ! to override)Điều này là do vim đánh dấu tệp là "không được chỉnh sửa" khi chúng tôi thay đổi tên của tệp. với :filelệnh.
  2. Chúng ta phải cố gắng giữ tên tệp thay thế bằng :keepaltlệnh. Khi chúng tôi cố gắng chỉnh sửa vimrc trong khi chỉnh sửa 'foo.bar', chúng tôi hy vọng tên tệp thay thế sẽ là 'foo.bar'. Nhưng nếu chúng ta tạo một bộ đệm và thay đổi tên, tên tệp thay thế sẽ không phải là "foo.bar" mà là tên cũ của bộ đệm 'vimrc'. Thậm chí tệ hơn, bộ đệm cũ sẽ được để lại như unlisted-bufferhoặc inactive-buffer. Đó là lý do tại sao chúng ta nên sử dụng :keepaltlệnh để giữ tên tệp thay thế như chúng ta mong đợi và đặt bufhiddentùy chọn là wipexóa sạch bộ đệm cũ.

Nếu chữ in hoa trong tên lệnh (tất cả các lệnh do người dùng xác định nên bắt đầu bằng chữ in hoa) không liên quan đến chúng tôi, tốt hơn là sử dụng nó. Bởi vì nó không tạo ra bộ đệm, chúng tôi không có gánh nặng cho việc quản lý bộ đệm. Chỉ cần chuyển tên tệp cho vim và xem cách vim xử lý nó.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.