Vim Tips Wiki
Register
Advertisement

Proposed tip Please edit this page to improve it, or add your comments below (do not use the discussion page).

Please use new tips to discuss whether this page should be a permanent tip, or whether it should be merged to an existing tip.
created August 7, 2009 · complexity basic · author Michael.Eriksson · version 7.0

Why use an image editor when you can create a favicon using Vim and have WYSIWYG editing? This tip shows a Vim script to generate a portable pixmap format (PPM) text file that can be used to create an icon using a tool such as Netpbm. In addition, syntax commands are provided that highlight the source text file to give WYSIWYG editing (the screen shows how the icon will appear while the text is edited).

Procedure

As a simple example, an icon for a two-color 7x5 Swedish flag will be created. Make a file called flag.txt containing the following (these define the colors, B = blue and Y = yellow; note that each line has a space before the first letter):

 B B Y B B B B
 B B Y B B B B
 Y Y Y Y Y Y Y
 B B Y B B B B
 B B Y B B B B

Make a file called append-colors.vim containing this Vim script:

" Basic colors from rgb.txt.
let colors = {
  \ 'k' : '0 0 0',
  \ 'b' : '0 0 139',
  \ 'g' : '0 100 0',
  \ 'c' : '0 139 139',
  \ 'r' : '139 0 0',
  \ 'm' : '139 0 139',
  \ 'y' : '165 42 42',
  \ 'w' : '211 211 211',
  \ 'K' : '169 169 169',
  \ 'B' : '0 0 255',
  \ 'G' : '0 255 0',
  \ 'C' : '0 255 255',
  \ 'R' : '255 0 0',
  \ 'M' : '255 0 255',
  \ 'Y' : '255 255 0',
  \ 'W' : '255 255 255'}

" Append lines to current buffer consisting of header (three lines):
"   'P1'=PBM (B&W) 'P2'=PGM (greyscale) 'P3'=PPM (full-color)
"   width height (two numbers)
"   color_depth  (one number)
" then the lines from translating each input letter to its color triple.
function! AppendColors(data_file)
  call append(line('$'), ['P3', '7 5', '255'])
  for line in readfile(a:data_file)
    for letter in split(line)
      call append(line('$'), g:colors[letter])
    endfor
  endfor
endfunction
command! -nargs=1 -complete=file AppendColors call AppendColors('<args>')

In Vim, enter the following commands to generate the output file:

:new
:so append-colors.vim
:AppendColors flag.txt
:w flag.ppm

The above command creates file flag.ppm by translating the letters in flag.txt to the color code numbers defined in the colors dictionary in the script. The script specifies a 7x5 pixel size.

 TO DO 

  • Briefly mention using ppmtowinicon to create the icon (but my first attempt gave a garbled output).

WYSWIG editing

Edit file flag.txt and enter the following commands:

:syntax clear
:syntax match Yellow " Y"
:syntax match Blue   " B"
:highlight Yellow guibg=#FFFF00 guifg=#FFFF00
:highlight Blue   guibg=#006FFD guifg=#006FFD

This will highlight " Y" (space then Y) in yellow, and " B" (space then B) in blue. The colors are solid (foreground = background).

An easy way to enter the commands would be to save the above lines in file flag-syntax.vim, then edit flag.txt and enter the command:

:so flag-syntax.vim

WYSWIG editing with full-featured syntax file

The file flag.txt should be like the following (only characters following "outputLine" are highlighted; other lines are not affected):

outputLine  B B Y B B B B
outputLine  B B Y B B B B
outputLine  Y Y Y Y Y Y Y
outputLine  B B Y B B B B
outputLine  B B Y B B B B

Source the following syntax script when editing flag.txt:

if version < 600
  syntax clear
elseif exists('b:current_syntax')
  finish
endif

runtime! syntax/sh.vim
unlet b:current_syntax

syn region ppmOutputline
 \ matchgroup=ppmKeyword
 \ keepend
 \ start=/^\s*outputLine\>/
 \ end=/$/
 \ contains=ppmBlack,ppmDarkblue,ppmDarkgreen,ppmDarkcyan,ppmDarkred,ppmDarkmagenta,
    \ppmBrown,ppmLightgrey,ppmDarkgrey,ppmBlue,ppmGreen,ppmCyan,ppmRed,ppmMagenta,
    \ppmYellow,ppmWhite

syn match ppmBlack       /\C k/ contained
syn match ppmDarkblue    /\C b/ contained
syn match ppmDarkgreen   /\C g/ contained
syn match ppmDarkcyan    /\C c/ contained
syn match ppmDarkred     /\C r/ contained
syn match ppmDarkmagenta /\C m/ contained
syn match ppmBrown       /\C y/ contained
syn match ppmLightgrey   /\C w/ contained
syn match ppmDarkgrey    /\C K/ contained
syn match ppmBlue        /\C B/ contained
syn match ppmGreen       /\C G/ contained
syn match ppmRed         /\C R/ contained
syn match ppmMagenta     /\C M/ contained
syn match ppmYellow      /\C Y/ contained
syn match ppmWhite       /\C W/ contained

if version >= 508 || !exists('did_ppm_syntax_inits')
 if version < 508
  let did_ppm_syntax_inits = 1
  command -nargs=+ HiSet hi <args>
 else
  command -nargs=+ HiSet hi def <args>
 endif
 HiSet ppmBlack       ctermbg=Black       ctermfg=LightGrey     guibg=black       guifg=white
 HiSet ppmDarkblue    ctermbg=DarkBlue    ctermfg=LightGrey     guibg=darkblue    guifg=white
 HiSet ppmDarkGreen   ctermbg=DarkGreen   ctermfg=LightGrey     guibg=darkgreen   guifg=white
 HiSet ppmDarkCyan    ctermbg=DarkCyan    ctermfg=LightGrey     guibg=darkcyan    guifg=white
 HiSet ppmDarkRed     ctermbg=DarkRed     ctermfg=LightGrey     guibg=darkred     guifg=white
 HiSet ppmDarkmagenta ctermbg=DarkMagenta ctermfg=LightGrey     guibg=darkmagenta guifg=white
 HiSet ppmBrown       ctermbg=Brown       ctermfg=LightGrey     guibg=brown       guifg=white
 HiSet ppmLightgrey   ctermbg=LightGrey   ctermfg=Black         guibg=lightgrey   guifg=black
 HiSet ppmDarkgrey    ctermbg=DarkGrey    ctermfg=White         guibg=darkgrey    guifg=white
 HiSet ppmBlue        ctermbg=Blue        ctermfg=White         guibg=blue        guifg=white
 HiSet ppmCyan        ctermbg=Cyan        ctermfg=DarkGrey      guibg=cyan        guifg=white
 HiSet ppmRed         ctermbg=Red         ctermfg=White         guibg=red         guifg=black
 HiSet ppmMagenta     ctermbg=Magenta     ctermfg=White         guibg=magenta     guifg=black
 HiSet ppmYellow      ctermbg=Yellow      ctermfg=DarkGrey      guibg=yellow      guifg=black
 HiSet ppmWhite       ctermbg=White       ctermfg=DarkGrey      guibg=white       guifg=black

 HiSet link ppmKeyword Keyword
 delcommand HiSet
endif

let b:current_syntax = "ppm"

See also

Comments

Old discussion

For anyone following this, I am keeping the following old discussion for a few days and will then delete it. I have added a comment at the end explaining what I have done. JohnBeckett 09:10, March 21, 2010 (UTC)

Due to my editing, this "tip" has become a "software package" with a bash script and a Vim syntax script. Maybe move to a subpage? --Tonymec 07:37, 27 August 2009 (UTC)

Thanks Tony, that's great. I think a few tricky and long tips are fine, so I would not put this on a subpage. I might reword the introduction so the big picture is somewhat clearer, and perhaps start with a very simple example, before any scripting is shown. We would just have a table of letters and the original :syntax statements, so people could easily see (in Vim) how a simple flag appears.
Can you please add a few words (here or in the tip) saying what your tricky syntax code achieves, compared with the original (bearing in mind that I know almost nothing about syntax files). We should not try to explain the details here, but roughly, what is being achieved with the "syn region..." and "contained" stuff?
1) It defines 16 colors, based on what a 16-color cterm can do, instead of only blue and yellow: this makes the syntax more general
2) It can be used in Console Vim, not only in gvim, since ctermfg= ctermbg= arguments have been provided
3) The "if" block at the start is what syntax scripts use nowadays (starting at Vim 6.0) rather than unconditionally using "syntax clear".
4) syn region, contains=, contained, are to make sure that the ppmBlack..ppmWhite highlights are only applied on lines starting with outputLine (optionally preceded by zero or more whitespace but nothing else).
5) Use of groups all starting ppm (maybe pnm would be better?) avoid conflicts with any other groups of the same name which might be defined elsewhere
I thought that maybe it might be nice to have the bash script source $1 if present instead of the set of outputLine statements (which would still be sourced "by default" otherwise, that would allow putting the outputLine statements (with the outputLine command, unlike what you did below) in a different file to be sourced by bash after defining the outputLine function. --Tonymec 15:15, 27 August 2009 (UTC)
It occurs to me that we could eliminate the bash script with some creative Vim coding ... not very important, but it might be interesting. JohnBeckett 08:53, 27 August 2009 (UTC)
maybe, but we would still need the "generator" script (which would be highlighted WYSIWIG), and then the ability to produce the PPM (or PBM, PGM, PNM) out of that. --Tonymec 15:15, 27 August 2009 (UTC)

I've gone a little crazy and done a Vim script (not checked much!). Perhaps this could be used instead of the bash script.

Code has been moved from this comment to the tip. JohnBeckett 09:10, March 21, 2010 (UTC)

That creates file flag.ppm from translating the letters in flag.txt to the color code numbers defined in the colors dictionary in the script. JohnBeckett 11:41, 27 August 2009 (UTC)

Note that this requires Vim 7, while the "two-script" package above should work with Vim 6.0 notwithstanding what the TipProposed template arguments say. (This is not important.) --Tonymec 15:15, 27 August 2009 (UTC)
oh, and BTW, hardcoding the dimensions as 7x5 in the functions makes it mandatory to have exactly 35 letters (no more, no less) in the data file. --Tonymec 15:47, 27 August 2009 (UTC)

P.S. I don't know much about syntax scripts either, but I know where they are described in the Vim help. I haven't tested yet that this actually works. Maybe we should ask Dr. Chip to have a look at this page? It's actually a rather "simple" syntax, not tricky at all compared to most others. --Tonymec 15:28, 27 August 2009 (UTC)


Explanation of recent changes:

  • I removed the bash script because the Vim script does the same job and is more appropriate for this wiki (btw, when testing, I had to remove the spaces in " = " in lines like k = '0 0 0', in case anyone tries the bash script from the previous version of this page).
  • The Vim script means it only works for Vim 7 but I am very happy with that (Vim 7 is nearly four years old and we are struggling to clean the tips for Vim 7, let alone handle any older versions).
  • I included the simple syntax highlighting commands first because they illustrate the essence of the tip. That is followed by Tony's code.

Any comments? JohnBeckett 09:10, March 21, 2010 (UTC)

Hm, I'd still prefer an AppendColors command with a parame-, er, user-settable height & width, but I'm not gonna go out of my way to get it, so this is OK by me. — Tonymec 12:19, March 21, 2010 (UTC)
Advertisement