Vim Tips Wiki
(Change <tt> to <code>, perhaps also minor tweak.)
 
(22 intermediate revisions by 3 users not shown)
Line 1: Line 1:
  +
{{TipNew
{{TipProposed
 
|id=0
+
|id=1629
|previous=0
+
|previous=1628
|next=0
+
|next=1630
|created=August 7, 2009
+
|created=2009
 
|complexity=basic
 
|complexity=basic
 
|author=Michael.Eriksson
 
|author=Michael.Eriksson
Line 11: Line 11:
 
|category2=
 
|category2=
 
}}
 
}}
  +
Why use an image editor when you can create a [[wikipedia:Favicon|favicon]] using Vim ''and'' have WYSIWYG editing? This tip shows a Vim script to generate a [[wikipedia:Netpbm format|portable pixmap format (PPM)]] text file that can be used to create an icon using a tool such as [[wikipedia:Netpbm|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).
I recently found myself in want of a favicon. Not wanting to mess around with typical WYSIWYG editors, I wrote a Bash script that generated a PPM file based on a data matrix corresponding to the individual pixels of the eventual favicon. By applying syntax highlightning to the data matrix, I effectively had a WYSIWYG display of the eventual image within Vim.
 
   
  +
==Procedure==
The true favicon was a five color, 32x32 matrix, mixing the Swedish and German flags (that I indeed did some extensive editing on, trying a number of variations). The below gives a simplified version using a 7x5 Swedish flag with two colors.
 
  +
As a simple example, an icon for a Swedish flag will be created. Make a file called <code>flag.txt</code> containing the following (the letters following "data" define the colors, other lines are ignored; <code>B</code> = blue and <code>Y</code> = yellow):
  +
<pre>
  +
Sample data for a 16x10 flag of Sweden.
   
  +
data B B B B B Y Y B B B B B B B B B
Bash (output to be directed into a .ppm file):
 
  +
data B B B B B Y Y B B B B B B B B B
  +
data B B B B B Y Y B B B B B B B B B
  +
data B B B B B Y Y B B B B B B B B B
  +
data Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y
  +
data Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y
  +
data B B B B B Y Y B B B B B B B B B
  +
data B B B B B Y Y B B B B B B B B B
  +
data B B B B B Y Y B B B B B B B B B
  +
data B B B B B Y Y B B B B B B B B B
  +
</pre>
  +
  +
Make a file called <code>append-colors.vim</code> containing this Vim script:
 
<pre>
 
<pre>
  +
" Basic colors from $VIMRUNTIME/rgb.txt
#!/bin/bash -u
 
# basic colors from rgb.txt
+
let colors = {
k = '0 0 0'
+
\ 'k' : '0 0 0',
b = '0 0 139'
+
\ 'b' : '0 0 139',
g = '0 100 0'
+
\ 'g' : '0 100 0',
c = '0 139 139'
+
\ 'c' : '0 139 139',
r = '139 0 0'
+
\ 'r' : '139 0 0',
m = '139 0 139'
+
\ 'm' : '139 0 139',
y = '165 42 42'
+
\ 'y' : '165 42 42',
w = '211 211 211'
+
\ 'w' : '211 211 211',
K = '169 169 169'
+
\ 'K' : '169 169 169',
B = '0 0 255'
+
\ 'B' : '0 0 255',
G = '0 255 0'
+
\ 'G' : '0 255 0',
C = '0 255 255'
+
\ 'C' : '0 255 255',
R = '255 0 0'
+
\ 'R' : '255 0 0',
M = '255 0 255'
+
\ 'M' : '255 0 255',
Y = '255 255 0'
+
\ 'Y' : '255 255 0',
W = '255 255 255'
+
\ 'W' : '255 255 255'}
   
  +
" Append lines to current buffer consisting of header (three lines):
function outputLine() {
 
for color in $*
+
" 'P3' = PPM (full color; numbers in ASCII decimal)
  +
" width height (two numbers)
do
 
  +
" color_depth (one number)
eval echo "\$$color"
 
  +
" then lines from translating each input letter to its color triple.
done
 
  +
" We translate only the letters that follow "data" at the start of a line.
}
 
  +
" Width = number of letters in first data item; height = number data items.
  +
function! AppendColors(data_file) abort
  +
let data = readfile(a:data_file)
  +
call filter(data, 'v:val=~#''^data\s''')
  +
call map(data, 'split(v:val)[1:]')
  +
let width_height = printf('%d %d', len(data[0]), len(data))
  +
call append(line('$'), ['P3', width_height, '255'])
  +
for columns in data
  +
call map(columns, 'g:colors[v:val]')
  +
call append(line('$'), columns)
  +
endfor
  +
endfunction
  +
command! -nargs=1 -complete=file AppendColors call AppendColors('<args>')
  +
</pre>
   
  +
In Vim, enter the following commands to generate the output file:
# PNM header
 
  +
<pre>
# P1=PBM (B&W) P2=PGM (greyscale) P3=PMM (full-color) P4-P7=binary
 
  +
:so append-colors.vim
echo 'P3'
 
  +
:new
# width / height
 
  +
:AppendColors flag.txt
echo '7 5'
 
  +
:w flag.ppm
# color depth
 
  +
</pre>
echo '255'
 
   
  +
The above commands creates file <code>flag.ppm</code> by translating the letters in <code>flag.txt</code> to the color code numbers defined in the <code>colors</code> dictionary in the script. The script reads the file into a list called <code>data</code>, then filters the list, keeping only the lines that start with "data" followed by a space or a tab character. Each element in the list (a data line) is then split into a list of whitespace-separated words, but the first word ("data") is omitted. The width and height of the icon are then determined from the number of columns and rows in the data. Then the ppm output data is appended to the current buffer.
# The below is the colored matrix. (Could be in a separate file.)
 
  +
outputLine B B Y B B B B
 
  +
With the Netpbm tools installed, you can create an icon file (say <code>flag.ico</code>) using:
outputLine B B Y B B B B
 
  +
<pre>
outputLine Y Y Y Y Y Y Y
 
  +
ppmtowinicon -output=flag.ico flag.ppm
outputLine B B Y B B B B
 
  +
</pre>
outputLine B B Y B B B B
 
  +
  +
==WYSIWYG editing==
  +
Edit file <code>flag.txt</code> and enter the following commands:
  +
<pre>
  +
:syntax clear
  +
:syntax match Yellow " Y"
  +
:syntax match Blue " B"
  +
:highlight Yellow guibg=#FFFF00 guifg=#FFFF00
  +
:highlight Blue guibg=#006FFD guifg=#006FFD
  +
</pre>
  +
  +
That will highlight "<code> Y</code>" (space then <code>Y</code>) in yellow, and "<code> B</code>" (space then <code>B</code>) in blue. The colors are solid (foreground = background).
  +
  +
An easy way to enter the commands would be to save the above lines in file <code>flag-syntax.vim</code>, then edit <code>flag.txt</code> and enter the command:
  +
<pre>
  +
:so flag-syntax.vim
  +
</pre>
  +
  +
To clear the highlighting, enter:
  +
<pre>
  +
:syntax clear
 
</pre>
 
</pre>
   
  +
==WYSIWYG editing with full-featured syntax file==
Syntax highlighting to apply to the Vim buffer to make the matrix appear in solid colors:
 
  +
An alternative to the above simple syntax commands would be to source the following syntax script while editing <code>flag.txt</code>:
 
<pre>
 
<pre>
 
if version < 600
 
if version < 600
 
syntax clear
 
syntax clear
elseif exists(b:current_syntax)
+
elseif exists('b:current_syntax')
 
finish
 
finish
 
endif
 
endif
   
  +
runtime! syntax/sh.vim
syn region ppmOutputline
 
  +
unlet b:current_syntax
  +
 
syn region ppmData
 
\ matchgroup=ppmKeyword
 
\ matchgroup=ppmKeyword
 
\ keepend
 
\ keepend
\ start=/^\s*outputline\>/
+
\ start=/^data\>/
 
\ end=/$/
 
\ end=/$/
 
\ contains=ppmBlack,ppmDarkblue,ppmDarkgreen,ppmDarkcyan,ppmDarkred,ppmDarkmagenta,
 
\ contains=ppmBlack,ppmDarkblue,ppmDarkgreen,ppmDarkcyan,ppmDarkred,ppmDarkmagenta,
Line 92: Line 146:
 
syn match ppmWhite /\C W/ contained
 
syn match ppmWhite /\C W/ contained
   
  +
if version >= 508 || !exists('did_ppm_syntax_inits')
hi def ppmBlack ctermbg=Black ctermfg=LightGrey guibg=black guifg=white
 
  +
if version < 508
hi def ppmDarkblue ctermbg=DarkBlue ctermfg=LightGrey guibg=darkblue guifg=white
 
  +
let did_ppm_syntax_inits = 1
hi def ppmDarkGreen ctermbg=DarkGreen ctermfg=LightGrey guibg=darkgreen guifg=white
 
  +
command -nargs=+ HiSet hi <args>
hi def ppmDarkCyan ctermbg=DarkCyan ctermfg=LightGrey guibg=darkcyan guifg=white
 
  +
else
hi def ppmDarkRed ctermbg=DarkRed ctermfg=LightGrey guibg=darkred guifg=white
 
  +
command -nargs=+ HiSet hi def <args>
hi def ppmDarkmagenta ctermbg=DarkMagenta ctermfg=LightGrey guibg=darkmagenta guifg=white
 
  +
endif
hi def ppmBrown ctermbg=Brown ctermfg=LightGrey guibg=brown guifg=white
 
hi def ppmLightgrey ctermbg=LightGrey ctermfg=Black guibg=lightgrey guifg=black
+
HiSet ppmBlack ctermbg=Black ctermfg=LightGrey guibg=black guifg=white
hi def ppmDarkgrey ctermbg=DarkGrey ctermfg=White guibg=darkgrey guifg=white
+
HiSet ppmDarkblue ctermbg=DarkBlue ctermfg=LightGrey guibg=darkblue guifg=white
hi def ppmBlue ctermbg=Blue ctermfg=White guibg=blue guifg=white
+
HiSet ppmDarkGreen ctermbg=DarkGreen ctermfg=LightGrey guibg=darkgreen guifg=white
hi def ppmCyan ctermbg=Cyan ctermfg=DarkGrey guibg=cyan guifg=white
+
HiSet ppmDarkCyan ctermbg=DarkCyan ctermfg=LightGrey guibg=darkcyan guifg=white
hi def ppmRed ctermbg=Red ctermfg=White guibg=red guifg=black
+
HiSet ppmDarkRed ctermbg=DarkRed ctermfg=LightGrey guibg=darkred guifg=white
hi def ppmMagenta ctermbg=Magenta ctermfg=White guibg=magenta guifg=black
+
HiSet ppmDarkmagenta ctermbg=DarkMagenta ctermfg=LightGrey guibg=darkmagenta guifg=white
hi def ppmYellow ctermbg=Yellow ctermfg=DarkGrey guibg=yellow guifg=black
+
HiSet ppmBrown ctermbg=Brown ctermfg=LightGrey guibg=brown guifg=white
hi def ppmWhite ctermbg=White ctermfg=DarkGrey guibg=white guifg=black
+
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
   
hi def link ppmKeyword Keyword
+
HiSet link ppmKeyword Keyword
  +
delcommand HiSet
  +
endif
   
  +
let b:current_syntax = "ppm"
 
</pre>
 
</pre>
   
  +
==See also==
A [http://www.aswedeingermany.de/50MetaInformation/50Favicon.html much larger write-up] with the full examples and some screen-shots is available. (I hope that the size justifies the external link.) The above should suffice to reproduce everything, however.
 
  +
*[http://www.aswedeingermany.de/50MetaInformation/50Favicon.html Larger example] using a bash script, with screen shots
   
 
==Comments==
 
==Comments==
'''TODO:'''
 
* Include "sh" syntax for lines other than "outputline"
 
* Foreground: same as bg (for solid colors) or distinct from bg (to facilitate editing)?
 
----
 
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? --[[User:Tonymec|Tonymec]] 07:37, 27 August 2009 (UTC)
 

Latest revision as of 06:40, 13 July 2012

Tip 1629 Printable Monobook Previous Next

created 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 Swedish flag will be created. Make a file called flag.txt containing the following (the letters following "data" define the colors, other lines are ignored; B = blue and Y = yellow):

Sample data for a 16x10 flag of Sweden.

data     B B B B B Y Y B B B B B B B B B
data     B B B B B Y Y B B B B B B B B B
data     B B B B B Y Y B B B B B B B B B
data     B B B B B Y Y B B B B B B B B B
data     Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y
data     Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y
data     B B B B B Y Y B B B B B B B B B
data     B B B B B Y Y B B B B B B B B B
data     B B B B B Y Y B B B B B B B B B
data     B B B B B Y Y B B B B B B B B B

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

" Basic colors from $VIMRUNTIME/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):
"   'P3' = PPM (full color; numbers in ASCII decimal)
"   width height (two numbers)
"   color_depth  (one number)
" then lines from translating each input letter to its color triple.
" We translate only the letters that follow "data" at the start of a line.
" Width = number of letters in first data item; height = number data items.
function! AppendColors(data_file) abort
  let data = readfile(a:data_file)
  call filter(data, 'v:val=~#''^data\s''')
  call map(data, 'split(v:val)[1:]')
  let width_height = printf('%d %d', len(data[0]), len(data))
  call append(line('$'), ['P3', width_height, '255'])
  for columns in data
    call map(columns, 'g:colors[v:val]')
    call append(line('$'), columns)
  endfor
endfunction
command! -nargs=1 -complete=file AppendColors call AppendColors('<args>')

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

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

The above commands 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 reads the file into a list called data, then filters the list, keeping only the lines that start with "data" followed by a space or a tab character. Each element in the list (a data line) is then split into a list of whitespace-separated words, but the first word ("data") is omitted. The width and height of the icon are then determined from the number of columns and rows in the data. Then the ppm output data is appended to the current buffer.

With the Netpbm tools installed, you can create an icon file (say flag.ico) using:

ppmtowinicon -output=flag.ico flag.ppm

WYSIWYG 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

That 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

To clear the highlighting, enter:

:syntax clear

WYSIWYG editing with full-featured syntax file[]

An alternative to the above simple syntax commands would be to source the following syntax script while 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 ppmData
 \ matchgroup=ppmKeyword
 \ keepend
 \ start=/^data\>/
 \ 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[]