diff --git a/runtime/doc/options.txt b/runtime/doc/options.txt
index 7475046e8855fa454a86e3f040082988b0f358a2..f1785bb85413996f31ec07473a30506fd57f0006 100644
--- a/runtime/doc/options.txt
+++ b/runtime/doc/options.txt
@@ -1884,8 +1884,9 @@ A jump table for the options with a short description can be found at |Q_op|.
 			parenthesis match.  When included "%" ignores
 			backslashes, which is Vi compatible.
 								*cpo-n*
-		n	When included, the column used for 'number' will also
-			be used for text of wrapped lines.
+		n	When included, the column used for 'number' and
+			'relativenumber' will also be used for text of wrapped
+			lines.
 								*cpo-o*
 		o	Line offset to search command is not remembered for
 			next search.
@@ -3608,7 +3609,8 @@ A jump table for the options with a short description can be found at |Q_op|.
 	|hl-Search|	 l  last search pattern highlighting (see 'hlsearch')
 	|hl-MoreMsg|	 m  |more-prompt|
 	|hl-ModeMsg|	 M  Mode (e.g., "-- INSERT --")
-	|hl-LineNr|	 n  line number for ":number" and ":#" commands
+	|hl-LineNr|	 n  line number for ":number" and ":#" commands, and
+			    when 'number' or 'relativenumber' option is set.
 	|hl-Question|	 r  |hit-enter| prompt and yes/no questions
 	|hl-StatusLine|	 s  status line of current window |status-line|
 	|hl-StatusLineNC| S  status lines of not-current windows
@@ -4871,6 +4873,7 @@ A jump table for the options with a short description can be found at |Q_op|.
 	When a long, wrapped line doesn't start with the first character, '-'
 	characters are put before the number.
 	See |hl-LineNr| for the highlighting used for the number.
+	When setting this option, 'relativenumber' is reset.
 
 						*'numberwidth'* *'nuw'*
 'numberwidth' 'nuw'	number	(Vim default: 4  Vi default: 8)
@@ -4879,13 +4882,14 @@ A jump table for the options with a short description can be found at |Q_op|.
 			{only available when compiled with the |+linebreak|
 			feature}
 	Minimal number of columns to use for the line number.  Only relevant
-	when the 'number' option is set or printing lines with a line number.
-	Since one space is always between the number and the text, there is
-	one less character for the number itself.
+	when the 'number' or 'relativenumber' option is set or printing lines
+	with a line number. Since one space is always between the number and
+	the text, there is one less character for the number itself.
 	The value is the minimum width.  A bigger width is used when needed to
-	fit the highest line number in the buffer.  Thus with the Vim default
-	of 4 there is room for a line number up to 999.  When the buffer has
-	1000 lines five columns will be used.
+	fit the highest line number in the buffer respectively the number of
+	rows in the window, depending on whether 'number' or 'relativenumber'
+	is set. Thus with the Vim default of 4 there is room for a line number
+	up to 999. When the buffer has 1000 lines five columns will be used.
 	The minimum value is 1, the maximum value is 10.
 	NOTE: 'numberwidth' is reset to 8 when 'compatible' is set.
 
@@ -5259,6 +5263,25 @@ A jump table for the options with a short description can be found at |Q_op|.
 	matches will be highlighted.  This is used to avoid that Vim hangs
 	when using a very complicated pattern.
 
+		*'relativenumber'* *'rnu'* *'norelativenumber'* *'nornu'*
+'relativenumber' 'rnu'	boolean	(default off)
+			local to window
+			{not in Vi}
+	Show the line number relative to the line with the cursor in front of
+	each line. Relative line numbers help you using the |count| you can
+	precede some vertical motion commands (e.g. j k + -) with, without
+	having to calculate it yourself. Especially useful in combination with
+	other commands (e.g. y d c < > gq gw =).
+	When the 'n' option is excluded from 'cpoptions' a wrapped
+	line will not use the column of line numbers (this is the default when
+	'compatible' isn't set).
+	The 'numberwidth' option can be used to set the room used for the line
+	number.
+	When a long, wrapped line doesn't start with the first character, '-'
+	characters are put before the number.
+	See |hl-LineNr| for the highlighting used for the number.
+	When setting this option, 'number' is reset.
+
 						*'remap'* *'noremap'*
 'remap'			boolean	(default on)
 			global
diff --git a/runtime/doc/quickref.txt b/runtime/doc/quickref.txt
index ceaef3be2999cad9cedf69c4c96366efe8de5c2a..075454eab202c981e9297a3b8f3891097df48a28 100644
--- a/runtime/doc/quickref.txt
+++ b/runtime/doc/quickref.txt
@@ -818,6 +818,7 @@ Short explanation of each option:		*option-list*
 'quoteescape'	  'qe'	    escape characters used in a string
 'readonly'	  'ro'	    disallow writing the buffer
 'redrawtime'	  'rdt'     timeout for 'hlsearch' and |:match| highlighting
+'relativenumber'  'rnu'	    show relative line number in front of each line
 'remap'			    allow mappings to work recursively
 'report'		    threshold for reporting nr. of lines changed
 'restorescreen'   'rs'	    Win32: restore screen when exiting
diff --git a/runtime/doc/syntax.txt b/runtime/doc/syntax.txt
index 08817c8f43a83f7e5401d4eb6bf1b92f2b2e4a39..5cf202df13efb8c532b098c8d023d29168d2cb5d 100644
--- a/runtime/doc/syntax.txt
+++ b/runtime/doc/syntax.txt
@@ -4203,7 +4203,7 @@ IncSearch	'incsearch' highlighting; also used for the text replaced with
 		":s///c"
 							*hl-LineNr*
 LineNr		Line number for ":number" and ":#" commands, and when 'number'
-		option is set.
+		or 'relativenumber' option is set.
 							*hl-MatchParen*
 MatchParen	The character under the cursor or just before it, if it
 		is a paired bracket, and its match. |pi_paren.txt|
diff --git a/runtime/doc/tags b/runtime/doc/tags
index f2d177ce6e22f34c6eccd52562e49e6952212b72..71611a72ef04914c4624f9b159e47e58dc429d80 100644
--- a/runtime/doc/tags
+++ b/runtime/doc/tags
@@ -559,6 +559,7 @@ $VIMRUNTIME	starting.txt	/*$VIMRUNTIME*
 'noprompt'	options.txt	/*'noprompt'*
 'nopvw'	options.txt	/*'nopvw'*
 'noreadonly'	options.txt	/*'noreadonly'*
+'norelativenumber'	options.txt	/*'norelativenumber'*
 'noremap'	options.txt	/*'noremap'*
 'norestorescreen'	options.txt	/*'norestorescreen'*
 'norevins'	options.txt	/*'norevins'*
@@ -567,6 +568,7 @@ $VIMRUNTIME	starting.txt	/*$VIMRUNTIME*
 'norightleftcmd'	options.txt	/*'norightleftcmd'*
 'norl'	options.txt	/*'norl'*
 'norlc'	options.txt	/*'norlc'*
+'nornu'	options.txt	/*'nornu'*
 'noro'	options.txt	/*'noro'*
 'nors'	options.txt	/*'nors'*
 'noru'	options.txt	/*'noru'*
@@ -708,6 +710,7 @@ $VIMRUNTIME	starting.txt	/*$VIMRUNTIME*
 'readonly'	options.txt	/*'readonly'*
 'redraw'	vi_diff.txt	/*'redraw'*
 'redrawtime'	options.txt	/*'redrawtime'*
+'relativenumber'	options.txt	/*'relativenumber'*
 'remap'	options.txt	/*'remap'*
 'report'	options.txt	/*'report'*
 'restorescreen'	options.txt	/*'restorescreen'*
@@ -717,6 +720,7 @@ $VIMRUNTIME	starting.txt	/*$VIMRUNTIME*
 'rightleftcmd'	options.txt	/*'rightleftcmd'*
 'rl'	options.txt	/*'rl'*
 'rlc'	options.txt	/*'rlc'*
+'rnu'	options.txt	/*'rnu'*
 'ro'	options.txt	/*'ro'*
 'rs'	options.txt	/*'rs'*
 'rtp'	options.txt	/*'rtp'*
diff --git a/runtime/doc/version7.txt b/runtime/doc/version7.txt
index 2ae9b0ea7b8a7e2befcb796e5c2fa553fbffee58..5f9da9346b153ffb9099499b4bd01cd297a3305b 100644
--- a/runtime/doc/version7.txt
+++ b/runtime/doc/version7.txt
@@ -643,8 +643,8 @@ Options: ~
 'maxmempattern'		maximum amount of memory to use for pattern matching
 'mkspellmem'		parameters for |:mkspell| memory use
 'mzquantum'		Time in msec to schedule MzScheme threads.
-'numberwidth'		Minimal width of the space used for the 'number'
-			option. (Emmanuel Renieris)
+'numberwidth'		Minimal width of the space used for the 'number' and
+			'relativenumber' option. (Emmanuel Renieris)
 'omnifunc'		The name of the function used for omni completion.
 'operatorfunc'		function to be called for |g@| operator
 'printmbcharset'	CJK character set to be used for :hardcopy
diff --git a/runtime/lang/menu_de_de.latin1.vim b/runtime/lang/menu_de_de.latin1.vim
index f374465186fdda011a8fdd321727190fe2c1dce0..6bfc0724840a96bddf9d6e8bf37c9067ea9e92c2 100644
--- a/runtime/lang/menu_de_de.latin1.vim
+++ b/runtime/lang/menu_de_de.latin1.vim
@@ -84,13 +84,14 @@ menutrans Toggle\ &Right\ Scrollbar			Rechten\ Rollbalken\ ein-\ und\ ausschalte
 menutrans F&ile\ Settings				&Datei-Einstellungen
 
 " Boolean options
-menutrans Toggle\ Line\ &Numbering<Tab>:set\ nu!	Anzeige\ der\ Zeilen&nummer\ ein-\ und\ ausschalten<Tab>:set\ nu!
-menutrans Toggle\ &List\ Mode<Tab>:set\ list!		&List-Modus\ ein-\ und\ ausschalten<Tab>:set\ list!
-menutrans Toggle\ Line\ &Wrap<Tab>:set\ wrap!		&Zeilenumbruch\ ein-\ und\ ausschalten<Tab>:set\ wrap!
-menutrans Toggle\ W&rap\ at\ word<Tab>:set\ lbr!	Umbruch\ an\ &Wortgrenzen\ ein-\ und\ ausschalten<Tab>:set\ lbr!
-menutrans Toggle\ &expand-tab<Tab>:set\ et!		&Erweiterung\ von\ Tabulatoren\ ein-\ und\ ausschalten<Tab>:set\ et!
-menutrans Toggle\ &auto-indent<Tab>:set\ ai!		&Automatische\ Einrückung\ ein-\ und\ ausschalten<Tab>:set\ ai!
-menutrans Toggle\ &C-indenting<Tab>:set\ cin!		&C-Einrückung\ ein-\ und\ ausschalten<Tab>:set\ cin!
+menutrans Toggle\ Line\ &Numbering<Tab>:set\ nu!		Anzeige\ der\ Zeilen&nummer\ ein-\ und\ ausschalten<Tab>:set\ nu!
+menutrans Toggle\ relati&ve\ Line\ Numbering<Tab>:set\ rnu!	Anzeige\ der\ relati&ven\ Zeilennummer\ ein-\ und\ ausschalten<Tab>:set\ rnu!
+menutrans Toggle\ &List\ Mode<Tab>:set\ list!			&List-Modus\ ein-\ und\ ausschalten<Tab>:set\ list!
+menutrans Toggle\ Line\ &Wrap<Tab>:set\ wrap!			&Zeilenumbruch\ ein-\ und\ ausschalten<Tab>:set\ wrap!
+menutrans Toggle\ W&rap\ at\ word<Tab>:set\ lbr!		Umbruch\ an\ &Wortgrenzen\ ein-\ und\ ausschalten<Tab>:set\ lbr!
+menutrans Toggle\ &expand-tab<Tab>:set\ et!			&Erweiterung\ von\ Tabulatoren\ ein-\ und\ ausschalten<Tab>:set\ et!
+menutrans Toggle\ &auto-indent<Tab>:set\ ai!			&Automatische\ Einrückung\ ein-\ und\ ausschalten<Tab>:set\ ai!
+menutrans Toggle\ &C-indenting<Tab>:set\ cin!			&C-Einrückung\ ein-\ und\ ausschalten<Tab>:set\ cin!
 
 " other options
 menutrans &Shiftwidth					&Schiebeweite
diff --git a/runtime/menu.vim b/runtime/menu.vim
index b7eccea301129d64ebd9d53636920758d06686c7..5b5246507cbd39c45d407825354fd3eb0c8b63cc 100644
--- a/runtime/menu.vim
+++ b/runtime/menu.vim
@@ -276,6 +276,7 @@ endfun
 
 " Boolean options
 an 20.440.100 &Edit.F&ile\ Settings.Toggle\ Line\ &Numbering<Tab>:set\ nu!	:set nu! nu?<CR>
+an 20.440.105 &Edit.F&ile\ Settings.Toggle\ relati&ve\ Line\ Numbering<Tab>:set\ rnu!	:set rnu! rnu?<CR>
 an 20.440.110 &Edit.F&ile\ Settings.Toggle\ &List\ Mode<Tab>:set\ list!	:set list! list?<CR>
 an 20.440.120 &Edit.F&ile\ Settings.Toggle\ Line\ &Wrap<Tab>:set\ wrap!	:set wrap! wrap?<CR>
 an 20.440.130 &Edit.F&ile\ Settings.Toggle\ W&rap\ at\ word<Tab>:set\ lbr!	:set lbr! lbr?<CR>
diff --git a/runtime/optwin.vim b/runtime/optwin.vim
index 7392b53bdc225252c2cd7ce8ec3b18d49dbb14eb..056d24c3a248b1b4d0aea947843a4ef81b29eaf8 100644
--- a/runtime/optwin.vim
+++ b/runtime/optwin.vim
@@ -365,6 +365,9 @@ call <SID>OptionG("lcs", &lcs)
 call append("$", "number\tshow the line number for each line")
 call append("$", "\t(local to window)")
 call <SID>BinOptionL("nu")
+call append("$", "relativenumber\tshow the relative line number for each line")
+call append("$", "\t(local to window)")
+call <SID>BinOptionL("rnu")
 if has("linebreak")
   call append("$", "numberwidth\tnumber of columns to use for the line number")
   call append("$", "\t(local to window)")
diff --git a/runtime/syntax/vim.vim b/runtime/syntax/vim.vim
index 22afcf401957eb16989e3b2bc924eef9330c8378..65de0b51b4ff301b3c5f67410d031dfd94fc9748 100644
--- a/runtime/syntax/vim.vim
+++ b/runtime/syntax/vim.vim
@@ -30,17 +30,17 @@ syn keyword vimOption contained	akm anti arshape awa backupskip bex bioskey brow
 syn keyword vimOption contained	al antialias autochdir background balloondelay bexpr bk bs casemap cfu cinkeys cmdwinheight commentstring conskey cscopepathcomp csprg cursorcolumn delcombine diffopt ea efm ep et fdc fdo ffs fk foldcolumn foldmethod formatoptions gd go guifont guitabtooltip hid hkp iconstring imd include inex isi js kp linebreak lm lz matchpairs maxmemtot mkspellmem mod mousef mouset nf oft pa path pheader previewheight printmbcharset pvw report rlc ruler sc scrolloff sel shcf shellslash shm showmatch sidescrolloff smartindent softtabstop spellfile splitright ssl statusline suffixes swf syntax tagbsearch tb term textwidth timeoutlen tm tr ttm ttyscroll undolevels vdir viewdir wa wd wi wildmode winfixwidth wiw wrap writedelay
 syn keyword vimOption contained	aleph ar autoindent backspace ballooneval bg bkc bsdir cb ch cino cmp compatible copyindent cscopeprg csqf cursorline dex digraph ead ei equalalways eventignore fde fdt fileencoding fkmap foldenable foldminlines formatprg gdefault gp guifontset helpfile hidden hl ignorecase imdisable includeexpr inf isident key langmap lines lmap ma matchtime mco ml modeline mousefocus mousetime nrformats ofu para pdev pi previewwindow printmbfont qe restorescreen ro rulerformat scb scrollopt selection shell shelltemp shortmess showmode siso smarttab sol spelllang spr ssop stl suffixesadd switchbuf ta taglength tbi termbidi tf title to ts tty ttytype updatecount ve viewoptions wak weirdinvert wig wildoptions winheight wm wrapmargin ws
 syn keyword vimOption contained	allowrevins arab autoread backup balloonexpr bh bl bsk ccv charconvert cinoptions cms complete cot cscopequickfix cst cwh dg dip eadirection ek equalprg ex fdi fen fileencodings flp foldexpr foldnestmax fp gfm grepformat guifontwide helpheight highlight hlg im imi incsearch infercase isk keymap langmenu linespace loadplugins macatsui maxcombine mef mls modelines mousehide mp nu omnifunc paragraphs penc pm printdevice printoptions quoteescape revins rs runtimepath scr scs selectmode shellcmdflag shelltype shortname showtabline sj smc sp spellsuggest sps st stmp sw sws tabline tagrelative tbidi termencoding tgst titlelen toolbar tsl ttybuiltin tw updatetime verbose viminfo warn wfh wildchar wim winminheight wmh wrapscan ww
-syn keyword vimOption contained	altkeymap arabic autowrite backupcopy bdir bin bomb bt cd ci cinw co completefunc cp cscopetag csto debug dict dir eb enc errorbells expandtab fdl fenc fileformat fml foldignore foldopen fs gfn grepprg guiheadroom helplang history hls imactivatekey iminsert inde insertmode iskeyword keymodel laststatus lisp lpl magic maxfuncdepth menuitems mm modifiable mousem mps number opendevice paste pex pmbcs printencoding prompt rdt ri 
+syn keyword vimOption contained	altkeymap arabic autowrite backupcopy bdir bin bomb bt cd ci cinw co completefunc cp cscopetag csto debug dict dir eb enc errorbells expandtab fdl fenc fileformat fml foldignore foldopen fs gfn grepprg guiheadroom helplang history hls imactivatekey iminsert inde insertmode iskeyword keymodel laststatus lisp lpl magic maxfuncdepth menuitems mm modifiable mousem mps number opendevice paste pex pmbcs printencoding prompt rdt ri relativenumber rnu
 
 " vimOptions: These are the turn-off setting variants {{{2
 syn keyword vimOption contained	noacd noallowrevins noantialias noarabic noarshape noautoread noaw noballooneval nobinary nobk nobuflisted nocin noconfirm nocopyindent nocscopeverbose nocuc nocursorline nodg noimdisable noeb noedcompatible noendofline noequalalways noesckeys noex noexrc nofk nofoldenable nogdefault nohid nohk nohkmapp nohls noic noignorecase noimc noimd noinf noinsertmode nojoinspaces nolazyredraw nolinebreak nolist nolpl noma nomagic noml nomodeline nomodified nomousef nomousehide nonumber noopendevice nopi nopreviewwindow nopvw noremap norevins norightleft norl noro noru nosb noscb noscs nosft noshelltemp noshortname noshowfulltag noshowmode nosm nosmartindent nosmd nosol nosplitbelow nospr nossl nostartofline noswapfile nota notagrelative notbi notbs noterse notextmode notgst notimeout noto notr nottybuiltin notx novisualbell nowarn noweirdinvert nowfw nowinfixheight nowiv nowrap nowrite nowritebackup
 syn keyword vimOption contained	noai noaltkeymap noar noarabicshape noautochdir noautowrite noawa nobeval nobiosk nobl nocf nocindent noconsk nocp nocst nocul nodeco nodiff noea noed noek noeol noerrorbells noet noexpandtab nofen nofkmap nogd noguipty nohidden nohkmap nohkp nohlsearch noicon noim noimcmdline noincsearch noinfercase nois nojs nolbr nolisp noloadplugins nolz nomacatsui nomh nomod nomodifiable nomore nomousefocus nonu noodev nopaste nopreserveindent noprompt noreadonly norestorescreen nori norightleftcmd norlc nors noruler nosc noscrollbind nosecure noshellslash noshiftround noshowcmd noshowmatch nosi nosmartcase nosmarttab nosn nospell nosplitright nosr nosta nostmp noswf notagbsearch notagstack notbidi notermbidi notextauto notf notildeop notitle notop nottimeout nottyfast novb nowa nowb nowfh nowildmenu nowinfixwidth nowmnu nowrapscan nowriteany nows
-syn keyword vimOption contained	noakm noanti noarab noari noautoindent noautowriteall nobackup nobin nobioskey nobomb noci nocompatible noconskey nocscopetag nocsverb nocursorcolumn nodelcombine nodigraph 
+syn keyword vimOption contained	noakm noanti noarab noari noautoindent noautowriteall nobackup nobin nobioskey nobomb noci nocompatible noconskey nocscopetag nocsverb nocursorcolumn nodelcombine nodigraph norelativenumber nornu
 
 " vimOptions: These are the invertible variants {{{2
 syn keyword vimOption contained	invacd invallowrevins invantialias invarabic invarshape invautoread invaw invballooneval invbinary invbk invbuflisted invcin invconfirm invcopyindent invcscopeverbose invcuc invcursorline invdg invdisable inveb invedcompatible invendofline invequalalways invesckeys invex invexrc invfk invfoldenable invgdefault invhid invhk invhkmapp invhls invic invignorecase invimc invimd invinf invinsertmode invjoinspaces invlazyredraw invlinebreak invlist invlpl invma invmagic invml invmodeline invmodified invmousef invmousehide invnumber invopendevice invpi invpreviewwindow invpvw invremap invrevins invrightleft invrl invro invru invsb invscb invscs invsft invshelltemp invshortname invshowfulltag invshowmode invsm invsmartindent invsmd invsol invsplitbelow invspr invssl invstartofline invswapfile invta invtagrelative invtbi invtbs invterse invtextmode invtgst invtimeout invto invtr invttybuiltin invtx invvisualbell invwarn invweirdinvert invwfw invwinfixheight invwiv invwrap invwrite invwritebackup
 syn keyword vimOption contained	invai invaltkeymap invar invarabicshape invautochdir invautowrite invawa invbeval invbiosk invbl invcf invcindent invconsk invcp invcst invcul invdeco invdiff invea inved invek inveol inverrorbells invet invexpandtab invfen invfkmap invgd invguipty invhidden invhkmap invhkp invhlsearch invicon invim invimcmdline invincsearch invinfercase invis invjs invlbr invlisp invloadplugins invlz invmacatsui invmh invmod invmodifiable invmore invmousefocus invnu invodev invpaste invpreserveindent invprompt invreadonly invrestorescreen invri invrightleftcmd invrlc invrs invruler invsc invscrollbind invsecure invshellslash invshiftround invshowcmd invshowmatch invsi invsmartcase invsmarttab invsn invspell invsplitright invsr invsta invstmp invswf invtagbsearch invtagstack invtbidi invtermbidi invtextauto invtf invtildeop invtitle invtop invttimeout invttyfast invvb invwa invwb invwfh invwildmenu invwinfixwidth invwmnu invwrapscan invwriteany invws
-syn keyword vimOption contained	invakm invanti invarab invari invautoindent invautowriteall invbackup invbin invbioskey invbomb invci invcompatible invconskey invcscopetag invcsverb invcursorcolumn invdelcombine invdigraph 
+syn keyword vimOption contained	invakm invanti invarab invari invautoindent invautowriteall invbackup invbin invbioskey invbomb invci invcompatible invconskey invcscopetag invcsverb invcursorcolumn invdelcombine invdigraph invrelativenumber invrnu
 
 " termcap codes (which can also be set) {{{2
 syn keyword vimOption contained	t_AB t_al t_bc t_ce t_cl t_Co t_cs t_Cs t_CS t_CV t_da t_db t_dl t_DL t_EI t_F1 t_F2 t_F3 t_F4 t_F5 t_F6 t_F7 t_F8 t_F9 t_fs t_IE t_IS t_k1 t_K1 t_k2 t_k3 t_K3 t_k4 t_K4 t_k5 t_K5 t_k6 t_K6 t_k7 t_K7 t_k8 t_K8 t_k9 t_K9 t_KA t_kb t_kB t_KB t_KC t_kd t_kD t_KD t_ke t_KE t_KF t_KG t_kh t_KH t_kI t_KI t_KJ t_KK t_kl t_KL t_kN t_kP t_kr t_ks t_ku t_le t_mb t_md t_me t_mr t_ms t_nd t_op t_RI t_RV t_Sb t_se t_Sf t_SI t_so t_sr t_te t_ti t_ts t_ue t_us t_ut t_vb t_ve t_vi t_vs t_WP t_WS t_xs t_ZH t_ZR
diff --git a/src/edit.c b/src/edit.c
index 33e580f1b91cadaba62e340ce9a440f56d289fc2..88943cd7f481637a775c3bb46e3bb70b4edae11c 100644
--- a/src/edit.c
+++ b/src/edit.c
@@ -6272,7 +6272,7 @@ comp_textwidth(ff)
 		    )
 	    textwidth -= 1;
 #endif
-	if (curwin->w_p_nu)
+	if (curwin->w_p_nu || curwin->w_p_rnu)
 	    textwidth -= 8;
     }
     if (textwidth < 0)
diff --git a/src/ex_cmds.c b/src/ex_cmds.c
index 2296c332ba49a38624abd6198999692045cbec42..1f9a7f2173b45f79900956982d80ee9968fc360e 100644
--- a/src/ex_cmds.c
+++ b/src/ex_cmds.c
@@ -3488,6 +3488,7 @@ do_ecmd(fnum, ffname, sfname, eap, newlnum, flags, oldwin)
 	curbuf->b_p_ma = FALSE;		/* not modifiable */
 	curbuf->b_p_bin = FALSE;	/* reset 'bin' before reading file */
 	curwin->w_p_nu = 0;		/* no line numbers */
+	curwin->w_p_rnu = 0;		/* no relative line numbers */
 #ifdef FEAT_SCROLLBIND
 	curwin->w_p_scb = FALSE;	/* no scroll binding */
 #endif
diff --git a/src/gui.c b/src/gui.c
index 2c307faaaadab988072207fa02c0fd2d8953e849..5b1a2ae08f868767e25c8dc7a54fa5566edf3ade 100644
--- a/src/gui.c
+++ b/src/gui.c
@@ -4412,7 +4412,7 @@ gui_update_horiz_scrollbar(force)
 	max += W_WIDTH(curwin) - 1;
 #endif
 	/* The line number isn't scrolled, thus there is less space when
-	 * 'number' is set (also for 'foldcolumn'). */
+	 * 'number' or 'relativenumber' is set (also for 'foldcolumn'). */
 	size -= curwin_col_off();
 #ifndef SCROLL_PAST_END
 	max -= curwin_col_off();
diff --git a/src/misc1.c b/src/misc1.c
index d476f31edd45cbdaffa528dccc8f3a4fed534d82..69bfe7dbe56fd7ac25cbac555d8e013917f34c45 100644
--- a/src/misc1.c
+++ b/src/misc1.c
@@ -1742,7 +1742,7 @@ plines_win_nofold(wp, lnum)
 	col += 1;
 
     /*
-     * Add column offset for 'number' and 'foldcolumn'.
+     * Add column offset for 'number', 'relativenumber' and 'foldcolumn'.
      */
     width = W_WIDTH(wp) - win_col_off(wp);
     if (width <= 0)
@@ -1803,7 +1803,7 @@ plines_win_col(wp, lnum, column)
 	col += win_lbr_chartabsize(wp, s, (colnr_T)col, NULL) - 1;
 
     /*
-     * Add column offset for 'number', 'foldcolumn', etc.
+     * Add column offset for 'number', 'relativenumber', 'foldcolumn', etc.
      */
     width = W_WIDTH(wp) - win_col_off(wp);
     if (width <= 0)
diff --git a/src/misc2.c b/src/misc2.c
index 949d7e21a89b57079e955fedf377cca5405fc711..8cd56830479d0a43d49b9dccde0cded8f6f5b914 100644
--- a/src/misc2.c
+++ b/src/misc2.c
@@ -468,6 +468,57 @@ decl(lp)
     return r;
 }
 
+/*
+ * Get the line number relative to the current cursor position, i.e. the
+ * difference between line number and cursor position. Only look for lines that
+ * can be visible, folded lines don't count.
+ */
+    linenr_T
+get_cursor_rel_lnum(wp, lnum)
+    win_T	*wp;
+    linenr_T	lnum;		    /* line number to get the result for */
+{
+    linenr_T	cursor = wp->w_cursor.lnum;
+    linenr_T	retval = 0;
+
+#ifdef FEAT_FOLDING
+    if (hasAnyFolding(wp))
+    {
+	if (lnum > cursor)
+	{
+	    while (lnum > cursor)
+	    {
+		(void)hasFolding(lnum, &lnum, NULL);
+		/* if lnum and cursor are in the same fold,
+		 * now lnum <= cursor */
+		if (lnum > cursor)
+		    retval++;
+		lnum--;
+	    }
+	}
+	else if (lnum < cursor)
+	{
+	    while (lnum < cursor)
+	    {
+		(void)hasFolding(lnum, NULL, &lnum);
+		/* if lnum and cursor are in the same fold,
+		 * now lnum >= cursor */
+		if (lnum < cursor)
+		    retval--;
+		lnum++;
+	    }
+	}
+	/* else if (lnum == cursor)
+	 *     retval = 0;
+	 */
+    }
+    else
+#endif
+	retval = lnum - cursor;
+
+    return retval;
+}
+
 /*
  * Make sure curwin->w_cursor.lnum is valid.
  */
diff --git a/src/move.c b/src/move.c
index de1a9e4de36785026c60dc8d98c43f7a4fe7f89b..4bdb694717eaeaa930622525fbe588b1d1542837 100644
--- a/src/move.c
+++ b/src/move.c
@@ -916,14 +916,14 @@ validate_cursor_col()
 }
 
 /*
- * Compute offset of a window, occupied by line number, fold column and sign
- * column (these don't move when scrolling horizontally).
+ * Compute offset of a window, occupied by absolute or relative line number,
+ * fold column and sign column (these don't move when scrolling horizontally).
  */
     int
 win_col_off(wp)
     win_T	*wp;
 {
-    return ((wp->w_p_nu ? number_width(wp) + 1 : 0)
+    return (((wp->w_p_nu || wp->w_p_rnu) ? number_width(wp) + 1 : 0)
 #ifdef FEAT_CMDWIN
 	    + (cmdwin_type == 0 || wp != curwin ? 0 : 1)
 #endif
@@ -949,13 +949,14 @@ curwin_col_off()
 
 /*
  * Return the difference in column offset for the second screen line of a
- * wrapped line.  It's 8 if 'number' is on and 'n' is in 'cpoptions'.
+ * wrapped line.  It's 8 if 'number' or 'relativenumber' is on and 'n' is in
+ * 'cpoptions'.
  */
     int
 win_col_off2(wp)
     win_T	*wp;
 {
-    if (wp->w_p_nu && vim_strchr(p_cpo, CPO_NUMCOL) != NULL)
+    if ((wp->w_p_nu || wp->w_p_rnu) && vim_strchr(p_cpo, CPO_NUMCOL) != NULL)
 	return number_width(wp) + 1;
     return 0;
 }
@@ -1218,17 +1219,22 @@ curs_columns(scroll)
     if (prev_skipcol != curwin->w_skipcol)
 	redraw_later(NOT_VALID);
 
+    /* Redraw when w_row changes and 'relativenumber' is set */
+    if (((curwin->w_valid & VALID_WROW) == 0 && (curwin->w_p_rnu
 #ifdef FEAT_SYN_HL
-    /* Redraw when w_virtcol changes and 'cursorcolumn' is set, or when w_row
-     * changes and 'cursorline' is set. */
-    if (((curwin->w_p_cuc && (curwin->w_valid & VALID_VIRTCOL) == 0)
-		|| (curwin->w_p_cul && (curwin->w_valid & VALID_WROW) == 0))
+	/* or when w_row changes and 'cursorline' is set. */
+						|| curwin->w_p_cul
+#endif
+	))
+#ifdef FEAT_SYN_HL
+	/* or when w_virtcol changes and 'cursorcolumn' is set */
+	|| (curwin->w_p_cuc && (curwin->w_valid & VALID_VIRTCOL) == 0)
+#endif
+	)
 # ifdef FEAT_INS_EXPAND
-	    && !pum_visible()
+	    if (!pum_visible())
 # endif
-	    )
-	redraw_later(SOME_VALID);
-#endif
+		redraw_later(SOME_VALID);
 
     curwin->w_valid |= VALID_WCOL|VALID_WROW|VALID_VIRTCOL;
 }
diff --git a/src/netbeans.c b/src/netbeans.c
index 94c1aaadf2edd603602d51ce5f07ec8f1bb28372..93a9aea75578ddfd55c7fda572cb3520354501dd 100644
--- a/src/netbeans.c
+++ b/src/netbeans.c
@@ -3143,7 +3143,8 @@ netbeans_button_release(int button)
 
     if (bufno >= 0 && curwin != NULL && curwin->w_buffer == curbuf)
     {
-	int col = mouse_col - W_WINCOL(curwin) - (curwin->w_p_nu ? 9 : 1);
+	int col = mouse_col - W_WINCOL(curwin)
+		  - ((curwin->w_p_nu || curwin->w_p_rnu) ? 9 : 1);
 	long off = pos2off(curbuf, &curwin->w_cursor);
 
 	/* sync the cursor position */
diff --git a/src/normal.c b/src/normal.c
index a19771b4fd3829e79096df84b98d3478c8764f9b..e02c81781550dd5dc0c5c8720e6ed8f3a2ca7c0f 100644
--- a/src/normal.c
+++ b/src/normal.c
@@ -7845,8 +7845,9 @@ nv_g_cmd(cap)
 	}
 	else
 	    i = curwin->w_leftcol;
-	/* Go to the middle of the screen line.  When 'number' is on and lines
-	 * are wrapping the middle can be more to the left. */
+	/* Go to the middle of the screen line.  When 'number' or
+	 * 'relativenumber' is on and lines are wrapping the middle can be more
+	 * to the left. */
 	if (cap->nchar == 'm')
 	    i += (W_WIDTH(curwin) - curwin_col_off()
 		    + ((curwin->w_p_wrap && i > 0)
diff --git a/src/option.c b/src/option.c
index f93d839cc611df1d04ceb59284527618d460e23f..c9cad32087b28c40c4834b79e037a297c13b6aaf 100644
--- a/src/option.c
+++ b/src/option.c
@@ -207,6 +207,7 @@
 # define PV_LBR		OPT_WIN(WV_LBR)
 #endif
 #define PV_NU		OPT_WIN(WV_NU)
+#define PV_RNU		OPT_WIN(WV_RNU)
 #ifdef FEAT_LINEBREAK
 # define PV_NUW		OPT_WIN(WV_NUW)
 #endif
@@ -2015,6 +2016,9 @@ static struct vimoption
 			    (char_u *)NULL, PV_NONE,
 #endif
 			    {(char_u *)2000L, (char_u *)0L} SCRIPTID_INIT},
+    {"relativenumber", "rnu", P_BOOL|P_VI_DEF|P_RWIN,
+			    (char_u *)VAR_WIN, PV_RNU,
+			    {(char_u *)FALSE, (char_u *)0L} SCRIPTID_INIT},
     {"remap",	    NULL,   P_BOOL|P_VI_DEF,
 			    (char_u *)&p_remap, PV_NONE,
 			    {(char_u *)TRUE, (char_u *)0L} SCRIPTID_INIT},
@@ -7230,10 +7234,18 @@ set_bool_option(opt_idx, varp, value, opt_flags)
 
     /* 'list', 'number' */
     else if ((int *)varp == &curwin->w_p_list
-	  || (int *)varp == &curwin->w_p_nu)
+	  || (int *)varp == &curwin->w_p_nu
+	  || (int *)varp == &curwin->w_p_rnu)
     {
 	if (curwin->w_curswant != MAXCOL)
 	    curwin->w_set_curswant = TRUE;
+
+	/* If 'number' is set, reset 'relativenumber'. */
+	/* If 'relativenumber' is set, reset 'number'. */
+	if ((int *)varp == &curwin->w_p_nu && curwin->w_p_nu)
+	    curwin->w_p_rnu = FALSE;
+	if ((int *)varp == &curwin->w_p_rnu && curwin->w_p_rnu)
+	    curwin->w_p_nu = FALSE;
     }
 
     else if ((int *)varp == &curbuf->b_p_ro)
@@ -9232,6 +9244,7 @@ get_varp(p)
 	case PV_FMR:	return (char_u *)&(curwin->w_p_fmr);
 #endif
 	case PV_NU:	return (char_u *)&(curwin->w_p_nu);
+	case PV_RNU:	return (char_u *)&(curwin->w_p_rnu);
 #ifdef FEAT_LINEBREAK
 	case PV_NUW:	return (char_u *)&(curwin->w_p_nuw);
 #endif
@@ -9417,6 +9430,7 @@ copy_winopt(from, to)
 #endif
     to->wo_list = from->wo_list;
     to->wo_nu = from->wo_nu;
+    to->wo_rnu = from->wo_rnu;
 #ifdef FEAT_LINEBREAK
     to->wo_nuw = from->wo_nuw;
 #endif
diff --git a/src/option.h b/src/option.h
index cfa7692cbac65bb70f1d55334a922e88352009f8..b635db17551d822f32b8fbdcf6047afe3dfbe161 100644
--- a/src/option.h
+++ b/src/option.h
@@ -1039,6 +1039,7 @@ enum
     , WV_LBR
 #endif
     , WV_NU
+    , WV_RNU
 #ifdef FEAT_LINEBREAK
     , WV_NUW
 #endif
diff --git a/src/proto/misc2.pro b/src/proto/misc2.pro
index 261ec8226df80a315d70265a4a71187db9b4aa86..5c4cc42100c9906a55ad94944341001ce3a3eb56 100644
--- a/src/proto/misc2.pro
+++ b/src/proto/misc2.pro
@@ -11,6 +11,7 @@ int incl __ARGS((pos_T *lp));
 int dec_cursor __ARGS((void));
 int dec __ARGS((pos_T *lp));
 int decl __ARGS((pos_T *lp));
+linenr_T get_cursor_rel_lnum __ARGS((win_T *wp, linenr_T lnum));
 void check_cursor_lnum __ARGS((void));
 void check_cursor_col __ARGS((void));
 void check_cursor __ARGS((void));
diff --git a/src/screen.c b/src/screen.c
index 7f929ac0f7ef11bc9bb31df91862a6c65216871d..72a93da64b820820cef9d7c90942e9a6acdc6612 100644
--- a/src/screen.c
+++ b/src/screen.c
@@ -423,9 +423,11 @@ update_screen(type)
 	check_for_delay(FALSE);
 
 #ifdef FEAT_LINEBREAK
-    /* Force redraw when width of 'number' column changes. */
+    /* Force redraw when width of 'number' or 'relativenumber' column
+     * changes. */
     if (curwin->w_redr_type < NOT_VALID
-	   && curwin->w_nrwidth != (curwin->w_p_nu ? number_width(curwin) : 0))
+	   && curwin->w_nrwidth != ((curwin->w_p_nu || curwin->w_p_rnu)
+				    ? number_width(curwin) : 0))
 	curwin->w_redr_type = NOT_VALID;
 #endif
 
@@ -871,8 +873,9 @@ win_update(wp)
 #endif
 
 #ifdef FEAT_LINEBREAK
-    /* Force redraw when width of 'number' column changes. */
-    i = wp->w_p_nu ? number_width(wp) : 0;
+    /* Force redraw when width of 'number' or 'relativenumber' column
+     * changes. */
+    i = (wp->w_p_nu || wp->w_p_rnu) ? number_width(wp) : 0;
     if (wp->w_nrwidth != i)
     {
 	type = NOT_VALID;
@@ -2118,7 +2121,7 @@ fold_line(wp, fold_count, foldinfo, lnum, row)
     /* Build the fold line:
      * 1. Add the cmdwin_type for the command-line window
      * 2. Add the 'foldcolumn'
-     * 3. Add the 'number' column
+     * 3. Add the 'number' or 'relativenumber' column
      * 4. Compose the text
      * 5. Add the text
      * 6. set highlighting for the Visual area an other text
@@ -2180,7 +2183,8 @@ fold_line(wp, fold_count, foldinfo, lnum, row)
 				 ScreenAttrs[off + (p) + ri] = v
 #endif
 
-    /* Set all attributes of the 'number' column and the text */
+    /* Set all attributes of the 'number' or 'relativenumber' column and the
+     * text */
     RL_MEMSET(col, hl_attr(HLF_FL), W_WIDTH(wp) - col);
 
 #ifdef FEAT_SIGNS
@@ -2206,18 +2210,27 @@ fold_line(wp, fold_count, foldinfo, lnum, row)
 #endif
 
     /*
-     * 3. Add the 'number' column
+     * 3. Add the 'number' or 'relativenumber' column
      */
-    if (wp->w_p_nu)
+    if (wp->w_p_nu || wp->w_p_rnu)
     {
 	len = W_WIDTH(wp) - col;
 	if (len > 0)
 	{
 	    int	    w = number_width(wp);
+	    long num;
 
 	    if (len > w + 1)
 		len = w + 1;
-	    sprintf((char *)buf, "%*ld ", w, (long)lnum);
+
+	    if (wp->w_p_nu)
+		/* 'number' */
+		num = (long)lnum;
+	    else
+		/* 'relativenumber', don't use negative numbers */
+		num = (long)abs((int)get_cursor_rel_lnum(wp, lnum));
+
+	    sprintf((char *)buf, "%*ld ", w, num);
 #ifdef FEAT_RIGHTLEFT
 	    if (wp->w_p_rl)
 		/* the line number isn't reversed */
@@ -3327,9 +3340,9 @@ win_line(wp, lnum, startrow, endrow, nochange)
 	    if (draw_state == WL_NR - 1 && n_extra == 0)
 	    {
 		draw_state = WL_NR;
-		/* Display the line number.  After the first fill with blanks
-		 * when the 'n' flag isn't in 'cpo' */
-		if (wp->w_p_nu
+		/* Display the absolute or relative line number. After the
+		 * first fill with blanks when the 'n' flag isn't in 'cpo' */
+		if ((wp->w_p_nu || wp->w_p_rnu)
 			&& (row == startrow
 #ifdef FEAT_DIFF
 			    + filler_lines
@@ -3343,8 +3356,18 @@ win_line(wp, lnum, startrow, endrow, nochange)
 #endif
 			    )
 		    {
+			long num;
+
+			if (wp->w_p_nu)
+			    /* 'number' */
+			    num = (long)lnum;
+			else
+			    /* 'relativenumber', don't use negative numbers */
+			    num = (long)abs((int)get_cursor_rel_lnum(wp,
+								    lnum));
+
 			sprintf((char *)extra, "%*ld ",
-						number_width(wp), (long)lnum);
+						number_width(wp), num);
 			if (wp->w_skipcol > 0)
 			    for (p_extra = extra; *p_extra == ' '; ++p_extra)
 				*p_extra = '-';
@@ -4707,7 +4730,8 @@ win_line(wp, lnum, startrow, endrow, nochange)
 	else
 	    --n_skip;
 
-	/* Only advance the "vcol" when after the 'number' column. */
+	/* Only advance the "vcol" when after the 'number' or 'relativenumber'
+	 * column. */
 	if (draw_state > WL_NR
 #ifdef FEAT_DIFF
 		&& filler_todo <= 0
@@ -9770,8 +9794,8 @@ win_redr_ruler(wp, always)
 
 #if defined(FEAT_LINEBREAK) || defined(PROTO)
 /*
- * Return the width of the 'number' column.
- * Caller may need to check if 'number' is set.
+ * Return the width of the 'number' and 'relativenumber' column.
+ * Caller may need to check if 'number' or 'relativenumber' is set.
  * Otherwise it depends on 'numberwidth' and the line count.
  */
     int
@@ -9781,7 +9805,13 @@ number_width(wp)
     int		n;
     linenr_T	lnum;
 
-    lnum = wp->w_buffer->b_ml.ml_line_count;
+    if (wp->w_p_nu)
+	/* 'number' */
+	lnum = wp->w_buffer->b_ml.ml_line_count;
+    else
+	/* 'relativenumber' */
+	lnum = wp->w_height;
+
     if (lnum == wp->w_nrwidth_line_count)
 	return wp->w_nrwidth_width;
     wp->w_nrwidth_line_count = lnum;
diff --git a/src/structs.h b/src/structs.h
index d434bfee458d3b7adc05a2eb05ec44576c25164b..72bd96cd44e9b8dca869c50bdb6e7c80ee610601 100644
--- a/src/structs.h
+++ b/src/structs.h
@@ -169,6 +169,8 @@ typedef struct
 #define w_p_list w_onebuf_opt.wo_list	/* 'list' */
     int		wo_nu;
 #define w_p_nu w_onebuf_opt.wo_nu	/* 'number' */
+    int		wo_rnu;
+#define w_p_rnu w_onebuf_opt.wo_rnu	/* 'relativenumber' */
 #ifdef FEAT_LINEBREAK
     long	wo_nuw;
 # define w_p_nuw w_onebuf_opt.wo_nuw	/* 'numberwidth' */
@@ -1907,7 +1909,8 @@ struct window_S
 				       recomputed */
 #endif
 #ifdef FEAT_LINEBREAK
-    int		w_nrwidth;	    /* width of 'number' column being used */
+    int		w_nrwidth;	    /* width of 'number' and 'relativenumber'
+				       column being used */
 #endif
 
     /*