Czy można używać dwóch różnych kolorów tła w jednym buforze vim?

20

Szukam możliwego rozwiązania dla zastosowania dwóch różnych kolorów tła w jednym buforze vim, w zależności od kontekstu, jak w tym wzniosłym przykładzie tekstu .

Jednym z takich przypadków jest odmienne kodowanie fragmentów kodu w plikach znaczników, aby wyróżniały się bardziej.

Jednak nigdy nie widziałem takiego przykładu z taką konfiguracją.

Czy to w ogóle możliwe w vimie?

Karolis Koncevičius
źródło
2
naprawdę chciałbym poznać odpowiedź na to pytanie, sugerowałbym, że będzie to możliwe dzięki podświetleniu składni tego postu na SO może być stos stackflowflow.com/questions/7033310/...
Nick J Adams

Odpowiedzi:

9

Ponieważ byłem ciekawy, jak dobrze by to zadziałało, zhakowałem coś razem tego rodzaju prace.

wprowadź opis zdjęcia tutaj

Jak wspomniano w komentarzach do wcześniejszej odpowiedzi, jedynym sposobem na to jest wypełnienie regionów spacjami; co dokładnie robimy; przed napisaniem usuwamy te spacje, więc nie powinieneś przeszkadzać innym.

Pamiętaj, że ten przykład jest bardzo specyficzny dla typu pliku przeceny!

Efekty uboczne :

  • Kopiowanie tekstu spowoduje również skopiowanie dużej ilości spacji
  • Używanie $i Endnie działa już zgodnie z oczekiwaniami (przechodzi do kolumny 80), a klucze takie jak ji kzachowują się inaczej.
  • Tło nie jest wyświetlane, gdy 'list'jest włączone
  • Całkowicie puste linie nie działają, musisz ręcznie dodać tabulator lub 4 spacje
  • ... może więcej?

Najpierw musisz dodać to do ~/.vim/after/syntax/markdown.vim:

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

Oczywiście możesz dostosować kolory do swoich upodobań ;-)

Następnie dodaj to do swojego 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()                            

Nie zamierzam wyjaśniać kodu wiersz po wierszu, komentarze powinny wyjaśnić ogólną treść ;-)

Martin Tournoij
źródło
Dziękuję za tę odpowiedź. Zaakceptowałem ją zamiast początkowej odpowiedzi udzielonej przez @Rich, ponieważ wydawała się bardziej kompletna. Wypróbuję to, ale nie jestem pewien, czy będę go używać z powodu wszystkich efektów ubocznych, więc nie obiecuję tutaj :) Wielkie dzięki za cały wysiłek!
Karolis Koncevičius
1
@ KarolisKoncevičius Thanks. Dodałem go również do mojego vimrc. To wydaje się miłe :-) Daj mi znać, jeśli napotkasz problemy.
Martin Tournoij,
Hahaha. Myślę, że to kwalifikuje się jako hack, ale nie jest tak okropne, jak się spodziewałem. Dobra robota. Oczywiście, skoro już zaszedłeś tak daleko, czy nie czujesz się zmuszony do rozwiązania problemów z j, k, $ itp. Poprzez ich odwzorowanie i usunięcie białej przestrzeni przed szarpnięciem? ;)
Rich
2
@Rich Tak, to hack. To sprawiło przyjemność ;-) Naprawienie niektórych kluczy (jakoś) również przyszło mi do głowy, ale spędziłem już sporo czasu i chcę najpierw sprawdzić, czy to w ogóle działa, a jeśli ja nawet się podoba, zanim jeszcze poświęcisz temu więcej czasu :-)
Martin Tournoij
2
@Carpetsmoker No cóż, kiedy ostatni raz niejasno zasugerowałem, że coś może być możliwe, odszedłeś i udało ci się, więc czekam na twoje solidne wielojęzyczne rozwiązanie za kilka tygodni.
Bogaty
13

Z pewnością możliwe jest użycie innego koloru tła dla elementów wyróżnionych składnią. Wystarczy zdefiniować guibgi ctermbgkolory w swoim hilightpoleceniu. Pierwszy z nich ustawia kolor tła dla GUI Vima, a drugi dla terminala Vima.

Ma to jednak istotne ograniczenie, ponieważ może ustawić kolory tła tylko dla znaków, które faktycznie istnieją w pliku.

Powoduje to, że kolor tła nie może rozciągać się poza koniec tekstu w linii do krawędzi okna, więc kolorowanie bloków kodu pokazanych w twoim przykładzie nie jest możliwe:

Przykład kolorowania tła możliwy w Vimie

Możesz także zmienić kolor tła całych linii za pomocą funkcji Znak. (Patrz linehlw :help sign.txt)

Przykład kolorowania tła za pomocą znaków

Należy jednak pamiętać, że:

  1. Wymaga to napisania kodu do umieszczenia znaków w każdym wierszu, który musi być pokolorowany, i aktualizowania ich wraz ze zmianą zawartości pliku,

  2. Domyślnie podczas umieszczania znaku kolumna znaku będzie wyświetlana po lewej stronie okna. Można zmienić kolorystykę kolumny znaku za pomocą SignColumngrupy wyróżnień, aw nowszych wersjach Vima można ją całkowicie usunąć. (Patrz :help 'signcolumn'.)

Na przykład, aby dostosować rozwiązanie Carpetsmoker do korzystania z (bardziej niezawodnego) mechanizmu znakowania , możesz wykonać następujące czynności:

" 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()

Upraszcza to nieco kod i ma mniej zastrzeżeń niż wersja Carpetsmokera.

@ChristianBrabandt „s DynamicSigns plugin sprawia, że korzystanie z funkcji znak dla tego celu łatwiejszego: on opisuje, jak go używać, aby zrobić w tej odpowiedzi .

Bogaty
źródło
1
+1 za odpowiedź. Jednak (i ​​popraw mnie, jeśli się mylę), ale guibgdziała tylko dla gvim, prawda?
Karolis Koncevičius
1
@Karolis Tak. W przypadku terminalu Vim należy użyć ctermbg, jak wspomniano.
Bogaty
1
Jeśli użyjesz fałd, otrzymasz to, co chcesz: fałdy mają inny kolor bg, ale można to osiągnąć, wypełniając tło znakami spacji, które mają inny zestaw kolorów bg ... To powoduje pewne skutki uboczne: kopiowanie / paste nie będzie już działać poprawnie (ponieważ kopiuje również wiele znaków spacji, w ten sposób możesz to sprawdzić samodzielnie).
Martin Tournoij
@Rich, dzięki za odpowiedź. Chociaż nie jest to idealne rozwiązanie (pod względem wyróżniania bloków), w pełni odpowiada na pytanie, wykazując, że jest to możliwe. Odpowiedź zaakceptowana.
Karolis Koncevičius
3
Ktoś musiałby być naprawdę szalony, aby napisać taki skrypt.
joeytwiddle