Specifying a New Syntax

Let’s get back to mpc#GetPlaylist now. We have an odd problem when coming up with a syntax for our playlist’s text. We need to separate titles and names, but we also need to be able to tell which is which. To do that, we’ll need to use more specific delimiting characters—titles and names can contain the space character, so we can’t use that.

Here’s our solution: For each track in the playlist, we’ll append a couple of characters of the item type’s name, along with our trusty @ character, to the beginning and ending of each item. If mpc gives us Jim Cole as the artist our playlist will include that as follows:

 
@arJim Colear@

We’ll add two new functions to do this; one will encode track items in this syntax, and one will decode the syntax. Here they are; add them, and then we’ll go over them:

vsyntax/mpc/autoload/mpc.vim
 
function​! mpc#EncodeSong(item)
 
let​ item = ​split​(a:item, ​" @"​)
 
let​ song = {​'position'​: item[0],
 
'artist'​: ​'@ar'​ . item[1] . ​'ar@'​,
 
'album'​: ​'@al'​ . item[2] . ​'al@'​,
 
'title'​: ​'@ti'​ . item[3] . ​'ti@'​}
 
return​ song
 
endfunction
 
 
function​! mpc#DecodeSong(item)
 
let​ line_items = ​split​(substitute(a:item, ​' {2,}'​, ​' '​, ​'g'​), ​' @'​)
 
let​ song = {​'position'​: line_items[0],
 
'artist'​: line_items[1][2:-4],
 
'album'​: line_items[2][2:-4],
 
'title'​: line_items[3][2:-4]}
 
return​ song
 
endfunction

First, mpc#EncodeSong splits an item by the @ separator that we use when we get the playlist from mpc. It returns a Dictionary, with entries for each of the items that make up a track.

Then in mpc#DecodeSong, we take a different approach. In this function we’re dealing with items that mpc#GetPlaylist has formatted as tracks, and they’ll all have different amounts of padding between them. So we use substitute to replace all occurrences of two or more spaces with a single space, and then we split the result on the @ between each item. We return the result as a Dictionary.

Now we need to use these functions in mpc#GetPlaylist before we return the playlist text. In that function, change the highlighted lines:

vsyntax.1/mpc/autoload/mpc.vim
 
function​! mpc#GetPlaylist()
 
let​ ​command​ = ​"mpc --format '%position% @%artist% @%album% @%title%' playlist"
 
let​ [results, playlist] = [​split​(system(​command​), ​' '​), []]
 
let​ maxLengths = {​'position'​: [], ​'artist'​: [], ​'album'​: []}
 
 
for​ item in results​
*
call​ add(playlist, mpc#EncodeSong(item))
*
endfor
*
*
for​ track in playlist
*
call​ add(maxLengths[​'position'​], len(track.position))
*
call​ add(maxLengths[​'artist'​], len(track.artist))
*
call​ add(maxLengths[​'album'​], len(track.album))​
 
endfor
 
 
call​ ​sort​(maxLengths.position, ​"LargestNumber"​)
 
call​ ​sort​(maxLengths.artist, ​"LargestNumber"​)
 
call​ ​sort​(maxLengths.album, ​"LargestNumber"​)​
 
*
for​ track in playlist
*
if​(maxLengths.position[-1] + 1 > len(track.position))
*
let​ track.position = repeat(​' '​,
*
maxLengths.position[-1] - len(track.position))
*
. track.position
*
endif
*
let​ track.position .= ​' '
*
let​ track.artist .= repeat(​' '​,
*
maxLengths[​'artist'​][-1] + 2 - len(track.artist))
*
let​ track.album .= repeat(​' '​,
*
maxLengths[​'album'​][-1] + 2 - len(track.album))
*
endfor​​
 
 
return​ playlist
 
endfunction

This looks more complicated than it is. Let’s go through it.

At the beginning, we used to create a List for each track, using split on each item of the results from mpc. Now we instead call mpc#EncodeSong on those items. This is how we populate the playlist.

Next, we add the items’ lengths, via len, from each track in the playlist to the right List in maxLengths. We sort each List using LargestNumber.

In our last loop, we pad each of the items in each track. This uses maxLengths and the repeat function that we saw before.

To wrap this up, we need to write the :syntax and :highlight commands that will tell Vim what these items are and how to highlight them. Open the syntax file we created earlier, syntax/mpdv.vim. Add the following commands:

vsyntax.1/mpc/syntax/mpdv.vim
 
syntax​ region mpdArtist matchgroup=mpdArtistSyn start=/@​ar​/ end=/​ar​@/ concealends
 
syntax​ region mpdAlbum matchgroup=mpdAlbumSyn start=/@​al​/ end=/​al​@/ concealends
 
syntax​ region mpdTitle matchgroup=mpdTitleSyn start=/@ti/ end=/ti@/ concealends
 
 
highlight​ default mpdArtist ctermbg=234 ctermfg=lightgreen
 
guibg=#1c1c1c guifg=#5fff87
 
highlight​ default mpdAlbum ctermbg=234 ctermfg=lightblue
 
guibg=#1c1c1c guifg=#5fd7ff
 
highlight​ default mpdTitle ctermbg=234 ctermfg=lightmagenta
 
guibg=#1c1c1c guifg=#ffafff

We’re defining three groups: one each for artist, album, and title. In each group, we set the matchgroup groups and start and end regular-expression patterns, we set concealends. The key bit in each of these commands is of course the name of the syntax group, which comes right after the region keyword: the artist gets the group mpdArtist, album becomes mpdAlbum, and title is mpdTitle.

Now turn your attention to the final three lines: the :highlight commands. These syntax groups don’t really fall into any category of programming-language constructs, so rather than linking them to the conventional highlight groups, we highlight the syntax groups directly. But notice the argument with which we’re starting each :highlight command. When we include the default argument in a :highlight command, that command becomes the default way to highlight the group; in other words, it can be overwritten. If a user liked our colors overall but wanted the artist column to be displayed in red, he could add this line to his .vimrc:

 
highlight​ mpdArtist ctermfg=​red​ guifg=#FF0000

And Vim would ignore our choice of color in favor of this.

The last step before we can see our highlighting in action is for us to go to the filetype file and make sure that Vim handles this syntax correctly. Open ftplugin/mpdv.vim and add these lines below the buftype and statusline settings:

vsyntax.1/mpc/ftplugin/mpdv.vim
 
setlocal​ conceallevel=3
 
setlocal​ concealcursor=nvic

This sets conceallevel to hide our regions’ start and end patterns. We also set concealcursor so that it won’t show the patterns in any of the four major modes: normal, visual, insert, and command. Remember that those patterns are in the groups that we put as the matchgroup of the regions. Because we set concealends on those regions, the pattern groups will now be hidden, and all we’ll see will be the groups that each of those regions contains.

At long last, it’s time to try this out. Open Vim and run :call OpenMPC() again. You should see the beautifully highlighted playlist, as shown in Figure 1, The highlighted playlist.

images/HighlightedPlaylist01.png

Figure 1. The highlighted playlist

We now have our playlist interface close to finished. You also know a bit more about syntax and color scheme files than you did at the start of the chapter—but you’ve gone long enough calling all of your plugin’s functions by hand via the Vim command line. In the next chapter you’ll learn about writing Vim commands and how you can add your own mappings that call those commands.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.222.94.153