เป็นไปได้หรือไม่ที่จะใช้พื้นหลังสีสองแบบในบัฟเฟอร์กลุ่มเดียว?


20

ฉันกำลังมองหาวิธีแก้ปัญหาที่เป็นไปได้สำหรับการใช้สีพื้นหลังที่แตกต่างกันสองสีภายในบัฟเฟอร์ vim เดียวโดยขึ้นอยู่กับบริบทเช่นในตัวอย่างข้อความประเสริฐนี้

กรณีการใช้งานหนึ่งกรณีนั่นคือการโค้ดสีในไฟล์มาร์กอัปแตกต่างกันดังนั้นพวกเขาจึงโดดเด่นกว่า

อย่างไรก็ตามฉันไม่เคยเห็นตัวอย่างพร้อมการตั้งค่าเช่นนั้น

เป็นไปได้ทั้งหมดในกลุ่ม?


2
จริงๆอยากจะรู้ว่าคำตอบนี้ผมจะแนะนำว่ามันจะเป็นไปได้ด้วยการเน้นไวยากรณ์การโพสต์เกี่ยวกับเรื่องนี้ดังนั้นอาจเกี่ยวข้องstackoverflow.com/questions/7033310/...
นิคเจอดัมส์

คำตอบ:


9

เพราะฉันสงสัยว่ามันจะทำงานได้ดีแค่ไหนฉันจึงแฮกบางอย่างเข้าด้วยกัน

ป้อนคำอธิบายรูปภาพที่นี่

ดังที่ได้กล่าวไว้ในความคิดเห็นเกี่ยวกับคำตอบก่อนหน้านี้วิธีเดียวที่จะทำเช่นนี้คือการเติมภูมิภาคที่มีช่องว่าง ซึ่งเป็นสิ่งที่เราทำ ก่อนที่จะเขียนเราจะลบช่องว่างเหล่านี้ดังนั้นคุณไม่ควรรบกวนใครด้วย

โปรดทราบว่าตัวอย่างนี้เฉพาะเจาะจงมากสำหรับไฟล์ประเภท markdown!

ผลข้างเคียง :

  • การคัดลอกข้อความจะเป็นการคัดลอกช่องว่างจำนวนมาก
  • การใช้$และEndไม่ทำงานตามที่คาดไว้ (ไปที่คอลัมน์ 80) และปุ่มต่างๆเช่น jและkยังทำงานแตกต่างกัน
  • พื้นหลังไม่ปรากฏเมื่อ'list'เปิดใช้งาน
  • บรรทัดว่างเปล่าไม่ทำงานคุณต้องเพิ่มแท็บหรือช่องว่าง 4 ด้วยตนเอง
  • ... อาจจะมากกว่านี้?

ก่อนอื่นคุณต้องเพิ่มสิ่งนี้ใน~/.vim/after/syntax/markdown.vim:

syn clear markdownCodeBlock                                                 
syn region markdownCodeBlock start="    \|\t" end="$"                       
hi def markdownCodeBlock ctermbg=230 guibg=lightyellow                      

คุณสามารถปรับสีตามที่คุณต้องการแน่นอน ;-)

จากนั้นเพิ่มไปยัง vimrc ของคุณ:

fun! MarkdownBlocks()                                                       
    fun! s:fill(line)                                                       
        " Remove all trailing whitespace                                    
        let l:line = substitute(a:line, " *$", "", "")                      

        " Add trailing whitespace up to 'textwidth' length                  
        return l:line . repeat(' ', (&tw > 0 ? &tw : 80) - strdisplaywidth(l:line))
    endfun                                                                  

    " Get all lines in a list                                               
    let l:lines = getline(1, line('$'))                                     

    " Map s:fill() to the lines that are a code block                       
    call map(l:lines, 'v:val[0] == "\t" || v:val[:3] == "    " ? s:fill(v:val) : v:val')

    " Reset the buffer to the lines                                         
    call setline(1, l:lines)                                                
endfun                                                                      

" Remove all the trailing spaces                                            
fun! MarkdownBlocksClean()                                                  
    let l:save_cursor = getpos(".")                                         
    silent %s/^\(    \|\t\)\(.\{-}\)\( *\)$/\1\2/e                          
    call setpos('.', l:save_cursor)                                         
endfun                                                                      
au BufWritePre *.markdown call MarkdownBlocksClean()                        

" Set spaces on loading the file, leaving insert mode, and after writing it 
au FileType markdown call MarkdownBlocks()                                  
au InsertLeave *.markdown call MarkdownBlocks()                             
au BufWritePost *.markdown call MarkdownBlocks()                            

ฉันจะไม่อธิบายรหัสทีละบรรทัดความคิดเห็นควรให้ความสำคัญกับมันชัดเจน ;-)


ขอบคุณสำหรับคำตอบนี้ ฉันยอมรับมันแทนที่จะเป็นคำตอบเริ่มต้นที่ @Rich ให้เพราะมันดูสมบูรณ์กว่า ฉันจะลองใช้ แต่ไม่แน่ใจว่าฉันจะใช้เพราะผลข้างเคียงทั้งหมดดังนั้นจึงไม่มีคำสัญญาที่นี่ :) ขอบคุณมากสำหรับความพยายามทั้งหมด!
Karolis Koncevičius

1
@ KarolisKoncevičiusขอบคุณ ฉันเพิ่มลงใน vimrc ของฉันเช่นกัน ดูเหมือนว่าดี :-) แจ้งให้เราทราบหากคุณพบปัญหา
Martin Tournoij

ฮ่า ๆ ๆ ๆ ฉันคิดว่านี่เป็นคุณสมบัติที่แฮ็ก แต่ก็ไม่น่ากลัวเท่าที่ฉันคาดไว้ งานที่ดี. แน่นอนว่าตอนนี้คุณผ่านไปแล้วคุณไม่รู้สึกว่าถูกบังคับให้แก้ไขปัญหากับ j, k, $ ฯลฯ โดยทำการแมปใหม่และลบพื้นที่สีขาวก่อนที่จะทำการดึง ;)
รวย

2
@ ริชใช่มันแฮ็ค นั่นทำให้มันสนุกที่จะทำ ;-) การแก้ไขคีย์บางอย่าง (อย่างใด) ทำให้ฉันใจแคบเช่นกัน แต่ฉันใช้เวลาไปกับเรื่องนี้แล้วและต้องการดูว่ามันใช้งานได้จริงหรือไม่และถ้าฉัน ยิ่งกว่านั้นก่อนที่จะใช้เวลากับมันมากขึ้น :-)
Martin Tournoij

2
@Carpetsmoker เอาละครั้งสุดท้ายที่ฉันบอกเป็นนัย ๆ ว่ามีบางสิ่งที่เป็นไปได้ที่คุณจากไปและสร้างมันขึ้นมาดังนั้นฉันหวังว่าจะได้เห็นโซลูชันหลายภาษาที่แข็งแกร่งของคุณในอีกสองสามสัปดาห์
รวย

13

แน่นอนเป็นไปได้ที่จะใช้สีพื้นหลังที่แตกต่างกันสำหรับองค์ประกอบที่เน้นไวยากรณ์ เพียงกำหนดguibgและctermbgสีในhilightคำสั่งของคุณ อดีตตั้งค่าสีพื้นหลังสำหรับ GUI Vim และสีหลังสำหรับ Terminal Vim

อย่างไรก็ตามสิ่งนี้มีข้อ จำกัด ที่สำคัญที่สามารถกำหนดสีพื้นหลังสำหรับอักขระที่มีอยู่จริงในไฟล์เท่านั้น

ผลลัพธ์ของสิ่งนี้คือสีพื้นหลังไม่สามารถขยายผ่านจุดสิ้นสุดของข้อความบนบรรทัดไปที่ขอบหน้าต่างดังนั้นการระบายสีของบล็อครหัสที่แสดงในตัวอย่างของคุณจึงเป็นไปไม่ได้:

ตัวอย่างของการระบายสีพื้นหลังที่เป็นไปได้ใน Vim

คุณยังสามารถเปลี่ยนสีพื้นหลังของทั้งบรรทัดโดยใช้คุณสมบัติลงชื่อเข้าใช้ (ดูlinehlใน:help sign.txt)

ตัวอย่างของการระบายสีพื้นหลังด้วยสัญญาณ

อย่างไรก็ตามโปรดทราบว่า:

  1. การทำเช่นนั้นจำเป็นต้องเขียนรหัสเพื่อวางเครื่องหมายบนแต่ละบรรทัดที่ต้องมีสีและปรับปรุงเหล่านี้เมื่อเนื้อหาของไฟล์เปลี่ยนแปลง

  2. ตามค่าเริ่มต้นเมื่อวางสัญลักษณ์คอลัมน์สัญญาณจะปรากฏทางด้านซ้ายของหน้าต่าง เป็นไปได้ที่จะเปลี่ยนสีของคอลัมน์สัญญาณด้วยSignColumnกลุ่มไฮไลต์และในเวอร์ชันล่าสุดของ Vim จะสามารถลบออกได้ทั้งหมด (ดู:help 'signcolumn'.)

ตัวอย่างเช่นหากต้องการปรับเปลี่ยนโซลูชันของ Carpetsmokerเพื่อใช้กลไกสัญญาณ (มีประสิทธิภาพมากขึ้น) คุณสามารถทำสิ่งต่อไปนี้:

" Define a highlight group and a sign that uses it
highlight default markdownCodeBlock ctermbg=230 guibg=lightyellow
sign define codeblock linehl=markdownCodeBlock

" Use signs to highlight code blocks
function! MarkdownBlocks()
    function! s:applySign(idx, val)
        if a:val[0] == "\t" || a:val[:3] == "    "
            let l = a:idx + 1
            execute "sign place " . l . " line=" . l . " name=codeblock file=" . expand("%:p")
        endif
    endfunction

    " Remove old signs
    execute "sign unplace * file=" . expand("%:p")

    " Get all lines in a list
    let l:lines = getline(1, line('$'))
    " Add new signs
    call map(l:lines, function('s:applySign'))
endfunction

" Set signs on loading the file, leaving insert mode, and after writing it
au FileType markdown call MarkdownBlocks()
au InsertLeave *.markdown call MarkdownBlocks()
au BufWritePost *.markdown call MarkdownBlocks()

สิ่งนี้จะทำให้รหัสง่ายขึ้นและมี caveats น้อยกว่าเวอร์ชั่นของ Carpetsmoker

@ChristianBrabandt 's DynamicSignsปลั๊กอินทำให้การใช้คุณลักษณะการเข้าสู่ระบบเพื่อการนี้ได้ง่ายขึ้น: เขาอธิบายวิธีการใช้งานให้ทำเช่นนั้นในคำตอบนี้


1
+1 สำหรับคำตอบ อย่างไรก็ตาม (และแก้ไขให้ฉันถ้าฉันผิด) แต่guibgใช้ได้กับ gvim เท่านั้นใช่มั้ย
Karolis Koncevičius

1
@ Karolis ใช่ สำหรับ Terminal Vim คุณจำเป็นต้องใช้ctermbgตามที่ระบุไว้
รวย

1
หากคุณใช้การพับคุณจะได้รับสิ่งที่คุณต้องการ: การพับมีสี bg ที่แตกต่างกันอย่างไรก็ตามสามารถทำได้โดยการเติมพื้นหลังด้วยอักขระช่องว่างที่มีชุดสี bg ที่แตกต่างกัน ... ซึ่งทำให้เกิดผลข้างเคียง: คัดลอก / paste ไม่ทำงานอย่างถูกต้องอีกต่อไป (เนื่องจากจะคัดลอกอักขระช่องว่างจำนวนมากนี่เป็นวิธีที่คุณสามารถยืนยันได้ด้วยตัวคุณเอง)
Martin Tournoij

@ Rich ขอบคุณสำหรับคำตอบ แม้ว่ามันจะไม่ใช่โซลูชันที่สมบูรณ์แบบ (ในแง่ของการเน้นบล็อก) แต่ก็ตอบคำถามที่แสดงให้เห็นว่าสิ่งนี้เป็นไปได้อย่างเต็มที่ คำตอบได้รับการยอมรับ
Karolis Koncevičius

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