สามารถตรวจสอบการเปลี่ยนแปลงไฟล์แบบเรียลไทม์เป็นกลุ่มได้


107

คำถามของฉันคล้ายกับวิธีการตรวจสอบไฟล์ข้อความแบบเรียลไทม์ แต่ฉันต้องการทำแบบกลุ่ม ฉันรู้ว่าฉันสามารถอ่านไฟล์ use file ที่เปิดอยู่ได้tail -f sample.xmlและเมื่อมีการเขียนเนื้อหาใหม่ลงในไฟล์มันจะเขียนเนื้อหาใหม่ลงในหน้าจอของฉันด้วย ฉันสามารถให้กลุ่มเติมข้อมูลใหม่โดยอัตโนมัติเมื่อไฟล์ได้รับการอัปเดตได้หรือไม่?

คำตอบ:


103

คุณสามารถ :set autoreadเพื่อให้กลุ่มอ่านไฟล์เมื่อมีการเปลี่ยนแปลง อย่างไรก็ตาม (ขึ้นอยู่กับแพลตฟอร์มของคุณ) คุณต้องให้ความสำคัญ

จากความช่วยเหลือ:

เมื่อตรวจพบว่ามีการเปลี่ยนแปลงไฟล์ภายนอก Vim และไม่มีการเปลี่ยนแปลงภายใน Vim ให้อ่านอีกครั้งโดยอัตโนมัติ เมื่อไฟล์ถูกลบจะไม่เสร็จสิ้น


6
ขอบคุณสำหรับคำแนะนำ! ดูเหมือนว่าจะค่อนข้างดี แต่มันใช้ไม่ได้กับระบบของฉัน :( ฉันใช้ Mac10.6.2 iTerm กับ vim เวอร์ชัน 7.2.303 ที่คอมไพล์ด้วย MacVim ฉันจะลองแสดงความคิดเห็นเพิ่มเติมได้ไหม
แพทริค

เอิ่มมันค่อนข้างแปลก คุณใช้ macvim gui หรือรุ่นเทอร์มินัลหรือไม่ มันใช้งานได้สำหรับฉันด้วย macvim gui ที่ดาวน์โหลดมาพร้อมคอมไพล์ (ฉันต้องคลิกที่แอปเพื่อให้มันโฟกัสตามที่ฉันได้กล่าวไว้)
ปีเตอร์

1
ฉันกำลังทดสอบในเทอร์มินัลหลังจากที่ฉันใช้ gvim (MacVim GUI) ฟังก์ชั่นก็เริ่มทำงาน! อย่างที่คุณพูดไปฉันต้องเน้น gvim เพื่ออัปเดตเนื้อหา คุณมีเคล็ดลับในการอัปเดตโดยไม่ต้องโฟกัสหรือไม่? ขอบคุณสำหรับความช่วยเหลืออีกครั้ง
Patrick

3
ฉันไม่รู้วิธีแก้ปัญหานั้นน่าเสียดาย ฉันจะตะลึงถ้ากลุ่มสามารถทำได้โดยไม่ต้องเปลี่ยนโฟกัส - มันจะต้องมีกลุ่มในการสำรวจระบบไฟล์เพื่อดูว่ามีการเปลี่ยนแปลงเมื่อใด ฉันคิดว่าคุณต้องมีปลั๊กอินสำหรับสิ่งนั้น
ปีเตอร์

2
@ ปีเตอร์ฉันสร้างปลั๊กอินดังกล่าวเมื่อไม่นานมานี้ ดูคำถามนี้และคำตอบของฉันด้วย สำหรับรายละเอียดเพิ่มเติมเกี่ยวกับวิธีการautoreadทำงานและข้อ จำกัด
Martin Tournoij

63

ไม่รู้โดยอัตโนมัติ แต่คุณสามารถพิมพ์:

:e!

เพื่อโหลดไฟล์ซ้ำ


แม้ว่าวิธีนี้จะไม่อัปเดตเนื้อหาโดยอัตโนมัติ แต่จะแสดงเนื้อหาที่อัปเดต ขอบคุณสำหรับคำตอบ!
Patrick

32

ใส่สิ่งต่อไปนี้ใน.vimrc:

"ตรวจสอบหนึ่งครั้งหลังจากไม่มีการใช้งาน 4 วินาทีในโหมดปกติ
ตั้งค่า autoread                                                                                                                                                                                    
au CursorHold * checktime                                                                                                                                                                       

เยี่ยมมาก! ทำงานได้ดีแม้จะมีคำเตือนว่าคุณเปลี่ยนไฟล์นั้นตั้งแต่การโหลดครั้งล่าสุด
zoujyjs

2
คำตอบแรกไม่ได้ผลสำหรับฉัน แต่มันได้ผล! :-)
IonicăBizău

4
"ทุก 4 วินาที" ไม่เป็นความจริง การดำเนินการนี้จะตรวจสอบเพียงครั้งเดียวหลังจากไม่มีการใช้งาน 4 วินาทีในโหมดปกติ ดังนั้นหากคุณไม่ทำอะไรในบัฟเฟอร์อื่นเป็นเวลานานมันจะไม่ได้รับการอัปเดต แต่ถ้าคุณแค่เลื่อนเคอร์เซอร์แล้วรอ 4 วินาที อีกทางเลือกหนึ่งคือเรียก ": checktime" ด้วยตนเองเพื่ออัปเดต (หลังจากตั้งค่า autoread) น่าเสียดายที่ดูเหมือนจะไม่มีการสนับสนุนการทำโพลในกลุ่มดังนั้นจึงไม่มีคำตอบที่แท้จริงสำหรับคำถาม OP
David Ljung Madison Stellar

1
เพิ่งมาเจอเรื่องนี้ หากคุณเปลี่ยน checktime เพื่อเรียกใช้ฟังก์ชันที่กำหนดเองและเพิ่ม "call feedkeys (" lh ")" ต่อท้ายฟังก์ชันฟังก์ชันนี้จะเริ่มทำงานทุกๆ 4 วินาที
flukus

@DavidLjungMadison คุณพูดถูกฉันจะแก้ไขโพสต์เพื่อหลีกเลี่ยงความผิดพลาดนี้
Phan Hai Quang

10

เช่น @flukus กล่าวในความคิดเห็นสำหรับคำตอบก่อนหน้านี้ที่คุณทำได้call feedkeys["lh"](มันเลื่อนเคอร์เซอร์ไปทางขวาและกลับไปทางซ้ายซึ่ง Normaly จะไม่ทำอันตรายเมื่อดูไฟล์บันทึก)

ดังนั้นหากคุณรวมคำตอบที่เหลือเข้าด้วยกันคุณมี oneliner คุณสามารถเรียกใช้จาก ex (whithin vim) เมื่อจำเป็น:

:set autoread | au CursorHold * checktime | call feedkeys("lh")


(หากคุณต้องการข้าม (เกือบ) ไปยังจุดสิ้นสุดของไฟล์เพียงใช้ "G" แทน "lh" พร้อมปุ่มป้อน)

คำอธิบาย:
- autoread : อ่านไฟล์เมื่อมีการเปลี่ยนแปลงจากภายนอก (แต่มันไม่ทำงานด้วยตัวเองไม่มีตัวจับเวลาภายในหรืออะไรทำนองนั้นมันจะอ่านไฟล์ก็ต่อเมื่อ vim ดำเนินการเช่นคำสั่งในอดีต:!
- เวลาตรวจสอบ CursorHold * : เมื่อผู้ใช้ไม่ได้ย้ายเคอร์เซอร์ตามเวลาที่ระบุไว้ใน 'updatetime' (ซึ่งคือ 4000 มิลลิวินาทีโดยค่าเริ่มต้น) เวลาตรวจสอบจะถูกเรียกใช้ซึ่งตรวจสอบการเปลี่ยนแปลงจากภายนอกไฟล์
- เรียก feedkeys ("lh") : เคอร์เซอร์ถูกย้ายหนึ่งครั้งไปทางขวาและกลับไปทางซ้ายแล้วไม่มีอะไรเกิดขึ้น (... ซึ่งหมายความว่า CursorHold ถูกทริกเกอร์ซึ่งหมายความว่าเรามีการวนซ้ำ )

นอกจากนี้คุณสามารถ:set syntax=logtalkระบายสีบันทึก

หากต้องการหยุดการเลื่อนเมื่อใช้call feedkeys("G")ให้ดำเนินการ:set noautoread- ตอนนี้กลุ่มจะบอกว่าไฟล์มีการเปลี่ยนแปลง ans ถามว่าต้องการอ่านการเปลี่ยนแปลงหรือไม่)

(สิ่งนี้มีผลข้างเคียงหรือไม่?)

แก้ไข:ฉันเห็น side-effect อย่างหนึ่ง: ถ้ามีคนใช้ "G" es ที่ feedkey มันจะเลื่อนลงทุกบัฟเฟอร์ที่เปิดอยู่ในปัจจุบัน?! ดังนั้นจึงเป็นไปไม่ได้ที่จะทำงานในบัฟเฟอร์ด้านซ้ายของหน้าต่าง Splittet ในขณะที่มีบัฟเฟอร์ด้านขวาเลื่อนไฟล์บันทึกโดยอัตโนมัติ


4

ติดสิ่งนี้ไว้ใน. vimrc ของคุณและควรใช้งานได้เหมือนเจ้านาย (นำมาจาก: http://vim.wikia.com/wiki/Have_Vim_check_automatically_if_the_file_has_changed_externally )

" Function to Watch for changes if buffer changed on disk
function! WatchForChanges(bufname, ...)
  " Figure out which options are in effect
  if a:bufname == '*'
    let id = 'WatchForChanges'.'AnyBuffer'
    " If you try to do checktime *, you'll get E93: More than one match for * is given
    let bufspec = ''
  else
    if bufnr(a:bufname) == -1
      echoerr "Buffer " . a:bufname . " doesn't exist"
      return
    end
    let id = 'WatchForChanges'.bufnr(a:bufname)
    let bufspec = a:bufname
  end
  if len(a:000) == 0
    let options = {}
  else
    if type(a:1) == type({})
      let options = a:1
    else
      echoerr "Argument must be a Dict"
    end
  end
  let autoread    = has_key(options, 'autoread')    ? options['autoread']    : 0
  let toggle      = has_key(options, 'toggle')      ? options['toggle']      : 0
  let disable     = has_key(options, 'disable')     ? options['disable']     : 0
  let more_events = has_key(options, 'more_events') ? options['more_events'] : 1
  let while_in_this_buffer_only = has_key(options, 'while_in_this_buffer_only') ? options['while_in_this_buffer_only'] : 0
  if while_in_this_buffer_only
    let event_bufspec = a:bufname
  else
    let event_bufspec = '*'
  end
  let reg_saved = @"
  "let autoread_saved = &autoread
  let msg = "\n"
  " Check to see if the autocommand already exists
  redir @"
    silent! exec 'au '.id
  redir END
  let l:defined = (@" !~ 'E216: No such group or event:')
  " If not yet defined...
  if !l:defined
    if l:autoread
      let msg = msg . 'Autoread enabled - '
      if a:bufname == '*'
        set autoread
      else
        setlocal autoread
      end
    end
    silent! exec 'augroup '.id
      if a:bufname != '*'
        "exec "au BufDelete    ".a:bufname . " :silent! au! ".id . " | silent! augroup! ".id
        "exec "au BufDelete    ".a:bufname . " :echomsg 'Removing autocommands for ".id."' | au! ".id . " | augroup! ".id
        exec "au BufDelete    ".a:bufname . " execute 'au! ".id."' | execute 'augroup! ".id."'"
      end
        exec "au BufEnter     ".event_bufspec . " :checktime ".bufspec
        exec "au CursorHold   ".event_bufspec . " :checktime ".bufspec
        exec "au CursorHoldI  ".event_bufspec . " :checktime ".bufspec
      " The following events might slow things down so we provide a way to disable them...
      " vim docs warn:
      "   Careful: Don't do anything that the user does
      "   not expect or that is slow.
      if more_events
        exec "au CursorMoved  ".event_bufspec . " :checktime ".bufspec
        exec "au CursorMovedI ".event_bufspec . " :checktime ".bufspec
      end
    augroup END
    let msg = msg . 'Now watching ' . bufspec . ' for external updates...'
  end
  " If they want to disable it, or it is defined and they want to toggle it,
  if l:disable || (l:toggle && l:defined)
    if l:autoread
      let msg = msg . 'Autoread disabled - '
      if a:bufname == '*'
        set noautoread
      else
        setlocal noautoread
      end
    end
    " Using an autogroup allows us to remove it easily with the following
    " command. If we do not use an autogroup, we cannot remove this
    " single :checktime command
    " augroup! checkforupdates
    silent! exec 'au! '.id
    silent! exec 'augroup! '.id
    let msg = msg . 'No longer watching ' . bufspec . ' for external updates.'
  elseif l:defined
    let msg = msg . 'Already watching ' . bufspec . ' for external updates'
  end
  echo msg
  let @"=reg_saved
endfunction

let autoreadargs={'autoread':1}
execute WatchForChanges("*",autoreadargs)

1
นี่คือคำตอบที่ต้องการเพื่อแก้ไขข้อบกพร่องของระบบอัตโนมัติของเทอร์มินัล
mcanfield

3
@mcanfield ไม่มันยังไม่ "เฝ้าดูการเปลี่ยนแปลง" คุณยังคงต้องเปิดใช้งานเป็นกลุ่มและยังคงมีการสำรวจ (ไม่ได้ดู) ในกลุ่มกิจกรรมที่ จำกัด CursorHoldมีการเรียกใช้ครั้งเดียว ดังนั้นหากคุณออกไปดื่มกาแฟหรือกำลังทำอะไรบางอย่างในหน้าต่างอื่นระบบจะไม่อัปเดต
Martin Tournoij

4
สคริปต์ที่ยังจะรวมเป็นกลุ่มปลั๊กอิน: กลุ่ม-AutoRead
stephen.hanson

1
@ stephen.hanson ขอบคุณสำหรับลิงค์ปลั๊กอินนั้นทำงานได้ดีสำหรับฉัน!
Tropilio


2

ถ้า unix + neovim

:term tail -f <filename>

เห็นได้ชัดว่าสิ่งนี้ใช้ไม่ได้กับทุกคน แต่เป็นวิธีที่ฉันทำ



0

VIM จะเตือนคุณเมื่อไฟล์ได้รับการอัปเดตเพื่อที่คุณจะได้ไม่เขียนทับการเปลี่ยนแปลงที่เกิดขึ้นตั้งแต่คุณเปิดไฟล์ มันจะแจ้งให้คุณโหลดไฟล์ซ้ำ


1
ขอบคุณสำหรับคำตอบของคุณ แต่กลุ่มไม่ได้เตือนฉันเมื่อไฟล์มีการเปลี่ยนแปลงในระบบของฉัน :(
แพทริค
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.