diff -r e363850c5e8f -r e0da6e4047e4 runtime/doc/options.txt
--- a/runtime/doc/options.txt	Tue Feb 08 20:05:26 2011 +0100
+++ b/runtime/doc/options.txt	Thu Feb 10 22:54:29 2011 +0100
@@ -1542,6 +1542,33 @@
 		:set columns=9999
 <	Minimum value is 12, maximum value is 10000.
 
+						*'columnview'* *'cov'*
+'columnview' 'cov'	string	(default "")
+			local to window
+			{not in Vi}
+			{not available when compiled without the |+hex|
+			features}
+	Number of characters grouped into one column.  This is a comma
+	separated list of sizes for each group of characters.  The first group
+	will result in a line group.  The other values state after how many
+	characters a column separation should be added.  If multiple
+	seperations occur at the same character location this separation is
+	incremented in size.  Here are a few example:
+	<emtpty>	Normal view. Don't use columns.
+	{break}		Only break the line after {break} characters.
+	{break},{count}	Place a separation every {count} characters.  And
+			break the line after {break} characters.
+	0,{count}	Place a separation every {count} characters.
+	{break},{count1},{count2},{countN}
+			Multiple {counts} can be added to make wider
+			separations.
+	A sane setting for hex editing: >
+		:set columnview=16,8,2
+<	The {break} is optional and can be left out if a comma is present.
+	The value of this first count is used a if it was 0.  This is useful
+	if no {break} should be specified.
+	The {break} option is ignored when the 'wrap' option is off.
+
 					*'comments'* *'com'* *E524* *E525*
 'comments' 'com'	string	(default
 				"s1:/*,mb:*,ex:*/,://,b:#,:%,:XCOMM,n:>,fb:-")
@@ -4480,7 +4507,8 @@
 	'wrapmargin' and 'textwidth', this does not insert <EOL>s in the file,
 	it only affects the way the file is displayed, not its contents.  The
 	value of 'showbreak' is used to put in front of wrapped lines.
-	This option is not used when the 'wrap' option is off or 'list' is on.
+	This option is not used when the 'wrap' option is off, 'list' is on or
+	'columnview' is set.
 	Note that <Tab> characters after an <EOL> are mostly not displayed
 	with the right amount of white space.
 
diff -r e363850c5e8f -r e0da6e4047e4 runtime/doc/quickref.txt
--- a/runtime/doc/quickref.txt	Tue Feb 08 20:05:26 2011 +0100
+++ b/runtime/doc/quickref.txt	Thu Feb 10 22:54:29 2011 +0100
@@ -641,6 +641,7 @@
 'cmdwinheight'	  'cwh'     height of the command-line window
 'colorcolumn'	  'cc'	    columns to highlight
 'columns'	  'co'	    number of columns in the display
+'columnview'	  'cov'	    separate groups character base on byte count
 'comments'	  'com'     patterns that can start a comment line
 'commentstring'   'cms'     template for comments; used for fold marker
 'compatible'	  'cp'	    behave Vi-compatible as much as possible
diff -r e363850c5e8f -r e0da6e4047e4 runtime/doc/various.txt
--- a/runtime/doc/various.txt	Tue Feb 08 20:05:26 2011 +0100
+++ b/runtime/doc/various.txt	Thu Feb 10 22:54:29 2011 +0100
@@ -328,7 +328,8 @@
    *+GUI_Motif*		Unix only: Motif |GUI|
    *+GUI_Photon*	QNX only:  Photon |GUI|
 m  *+hangul_input*	Hangul input support |hangul|
-B  *+hex*		Hex editing support. 'displaymode' and 'hexnumber'
+B  *+hex*		Hex editing support. 'displaymode', 'hexnumber' and
+			'columnview'
    *+iconv*		Compiled with the |iconv()| function
    *+iconv/dyn*		Likewise |iconv-dynamic| |/dyn|
 N  *+insert_expand*	|insert_expand| Insert mode completion
diff -r e363850c5e8f -r e0da6e4047e4 runtime/optwin.vim
--- a/runtime/optwin.vim	Tue Feb 08 20:05:26 2011 +0100
+++ b/runtime/optwin.vim	Thu Feb 10 22:54:29 2011 +0100
@@ -392,6 +392,9 @@
   call append("$", "displaymode\tdisplay type: \"\", \"dot\" or \"hex\"")
   call append("$", "\t(local to window)")
   call <SID>OptionL("dym")
+  call append("$", "columnview\column separations")
+  call append("$", "\t(local to window)")
+  call <SID>OptionL("cov")
 endif
 
 
diff -r e363850c5e8f -r e0da6e4047e4 src/charset.c
--- a/src/charset.c	Tue Feb 08 20:05:26 2011 +0100
+++ b/src/charset.c	Thu Feb 10 22:54:29 2011 +0100
@@ -829,21 +829,21 @@
  */
 
 #ifdef FEAT_HEX
-#define RET_WIN_BUF_CHARTABSIZE(wp, buf, p, col) \
+# define RET_WIN_BUF_CHARTABSIZE(wp, buf, p, col, sep) \
     if (*(p) == TAB && (!(wp)->w_p_list || lcs_tab1)) \
     { \
 	int ts; \
 	ts = (buf)->b_p_ts; \
-	return (int)(ts - (col % ts)); \
+	return (int)(ts - (col % ts)) + sep; \
     } \
     else if (*(wp)->w_p_dym == 'h') \
-	return 2; \
+	return 2 + sep; \
     else if (*(wp)->w_p_dym == 'd') \
-	return 1; \
+	return 1 + sep; \
     else \
-	return ptr2cells(p);
+	return ptr2cells(p) + sep;
 #else
-#define RET_WIN_BUF_CHARTABSIZE(wp, buf, p, col) \
+# define RET_WIN_BUF_CHARTABSIZE(wp, buf, p, col) \
     if (*(p) == TAB && (!(wp)->w_p_list || lcs_tab1)) \
     { \
 	int ts; \
@@ -861,7 +861,45 @@
     char_u	*p;
     colnr_T	col;
 {
-    RET_WIN_BUF_CHARTABSIZE(curwin, curbuf, p, col)
+# ifdef FEAT_HEX
+    int		sep = 0;
+    char_u	*line;
+    int		numberextra;
+    colnr_T	colmax;
+
+    line = curbuf->b_ml.ml_line_ptr;
+    if (STRLEN(line) > (p - line))
+    {
+	if (curwin->w_p_wrap && curwin->w_onebuf_opt.cov_break > 0
+		&& ((p - line + 1) % curwin->w_onebuf_opt.cov_break) == 0)
+	{
+	    numberextra = win_col_off(curwin);
+	    colmax = (colnr_T)(W_WIDTH(curwin) - numberextra);
+	    if (col <= colmax)
+		return colmax - col;
+	    numberextra = colmax;
+	    colmax += win_col_off2(curwin);
+	    return colmax - ((col - numberextra) % colmax);
+	}
+	else
+	{
+	    int i = 0;
+
+	    while (curwin->w_onebuf_opt.cov_sep[i])
+	    {
+		if (((p - line + 1) % curwin->w_onebuf_opt.cov_sep[i]) == 0)
+		    ++sep;
+		++i;
+	    }
+	}
+    }
+# endif
+
+    RET_WIN_BUF_CHARTABSIZE(curwin, curbuf, p, col
+# ifdef FEAT_HEX
+	    , sep
+# endif
+	    )
 }
 #endif
 
@@ -872,7 +910,45 @@
     char_u	*p;
     colnr_T	col;
 {
-    RET_WIN_BUF_CHARTABSIZE(wp, wp->w_buffer, p, col)
+# ifdef FEAT_HEX
+    int		sep = 0;
+    char_u	*line;
+    int		numberextra;
+    colnr_T	colmax;
+
+    line = wp->w_buffer->b_ml.ml_line_ptr;
+    if (STRLEN(line) > (p - line))
+    {
+	if (wp->w_p_wrap && wp->w_onebuf_opt.cov_break > 0
+		&& ((p - line + 1) % wp->w_onebuf_opt.cov_break) == 0)
+	{
+	    numberextra = win_col_off(curwin);
+	    colmax = (colnr_T)(W_WIDTH(curwin) - numberextra);
+	    if (col <= colmax)
+		return colmax - col;
+	    numberextra = colmax;
+	    colmax += win_col_off2(curwin);
+	    return colmax - ((col - numberextra) % colmax);
+	}
+	else
+	{
+	    int i = 0;
+
+	    while (wp->w_onebuf_opt.cov_sep[i])
+	    {
+		if (((p - line + 1) % wp->w_onebuf_opt.cov_sep[i]) == 0)
+		    ++sep;
+		++i;
+	    }
+	}
+    }
+# endif
+
+    RET_WIN_BUF_CHARTABSIZE(wp, wp->w_buffer, p, col
+# ifdef FEAT_HEX
+	    , sep
+# endif
+	    )
 }
 #endif
 
@@ -1052,11 +1128,49 @@
     if (!curwin->w_p_lbr && *p_sbr == NUL)
     {
 #endif
+#ifdef FEAT_HEX
+	int	    sep = 0;
+	char_u	    *line;
+#endif
 #ifdef FEAT_MBYTE
 	if (curwin->w_p_wrap)
 	    return win_nolbr_chartabsize(curwin, s, col, NULL);
 #endif
-	RET_WIN_BUF_CHARTABSIZE(curwin, curbuf, s, col)
+#ifdef FEAT_HEX
+	line = curbuf->b_ml.ml_line_ptr;
+	if (STRLEN(line) > (s - line))
+	{
+	    if (curwin->w_p_wrap && curwin->w_onebuf_opt.cov_break > 0
+		    && ((s - line + 1) % curwin->w_onebuf_opt.cov_break) == 0)
+	    {
+		int	    numberextra;
+		colnr_T	    colmax;
+		numberextra = win_col_off(curwin);
+		colmax = (colnr_T)(W_WIDTH(curwin) - numberextra);
+		if (col <= colmax)
+		    return colmax - col;
+		numberextra = colmax;
+		colmax += win_col_off2(curwin);
+		return colmax - ((col - numberextra) % colmax);
+	    }
+	    else
+	    {
+		int i = 0;
+
+		while (curwin->w_onebuf_opt.cov_sep[i])
+		{
+		    if (((s - line + 1) % curwin->w_onebuf_opt.cov_sep[i]) == 0)
+			++sep;
+		    ++i;
+		}
+	    }
+	}
+#endif
+	RET_WIN_BUF_CHARTABSIZE(curwin, curbuf, s, col
+#ifdef FEAT_HEX
+		, sep
+#endif
+		)
 #ifdef FEAT_LINEBREAK
     }
     return win_lbr_chartabsize(curwin, s, col, NULL);
@@ -1114,11 +1228,47 @@
     if (!wp->w_p_lbr && *p_sbr == NUL)
 #endif
     {
+#ifdef FEAT_HEX
+	int	    sep = 0;
+	char_u	    *line;
+#endif
 #ifdef FEAT_MBYTE
 	if (wp->w_p_wrap)
 	    return win_nolbr_chartabsize(wp, s, col, headp);
 #endif
-	RET_WIN_BUF_CHARTABSIZE(wp, wp->w_buffer, s, col)
+#ifdef FEAT_HEX
+	line = wp->w_buffer->b_ml.ml_line_ptr;
+	if (STRLEN(line) > (s - line))
+	{
+	    if (wp->w_p_wrap && wp->w_onebuf_opt.cov_break > 0
+		    && ((s - line + 1) % wp->w_onebuf_opt.cov_break) == 0)
+	    {
+		numberextra = win_col_off(curwin);
+		colmax = (colnr_T)(W_WIDTH(curwin) - numberextra);
+		if (col <= colmax)
+		    return colmax - col;
+		numberextra = colmax;
+		colmax += win_col_off2(curwin);
+		return colmax - ((col - numberextra) % colmax);
+	    }
+	    else
+	    {
+		int i = 0;
+
+		while (wp->w_onebuf_opt.cov_sep[i])
+		{
+		    if (((s - line + 1) % wp->w_onebuf_opt.cov_sep[i]) == 0)
+			++sep;
+		    ++i;
+		}
+	    }
+	}
+#endif
+	RET_WIN_BUF_CHARTABSIZE(wp, wp->w_buffer, s, col
+#ifdef FEAT_HEX
+		, sep
+#endif
+		)
     }
 
 #ifdef FEAT_LINEBREAK
@@ -1140,6 +1290,9 @@
 # ifdef FEAT_VERTSPLIT
 	    && wp->w_width != 0
 # endif
+# ifdef FEAT_HEX
+	    && *wp->w_p_cov == NUL
+# endif
        )
     {
 	/*
@@ -1237,17 +1390,54 @@
     int		*headp;
 {
     int		n;
+# ifdef FEAT_HEX
+    int		sep = 0;
+    char_u	*line;
+
+    line = wp->w_buffer->b_ml.ml_line_ptr;
+    if (STRLEN(line) > (s - line))
+    {
+	if (wp->w_p_wrap && wp->w_onebuf_opt.cov_break > 0
+		&& ((s - line + 1) % wp->w_onebuf_opt.cov_break) == 0)
+	{
+	    int		numberextra;
+	    colnr_T	colmax;
+	    numberextra = win_col_off(curwin);
+	    colmax = (colnr_T)(W_WIDTH(curwin) - numberextra);
+	    if (col <= colmax)
+		return colmax - col;
+	    numberextra = colmax;
+	    colmax += win_col_off2(curwin);
+	    return colmax - ((col - numberextra) % colmax);
+	}
+	else
+	{
+	    int i = 0;
+
+	    while (wp->w_onebuf_opt.cov_sep[i])
+	    {
+		if (((s - line + 1) % wp->w_onebuf_opt.cov_sep[i]) == 0)
+		    ++sep;
+		++i;
+	    }
+	}
+    }
+# endif
 
     if (*s == TAB && (!wp->w_p_list || lcs_tab1))
     {
 	n = wp->w_buffer->b_p_ts;
-	return (int)(n - (col % n));
+	n = (int)(n - (col % n));
+# ifdef FEAT_HEX
+	n += sep;
+# endif
+	return n;
     }
 # ifdef FEAT_HEX
     if (*wp->w_p_dym == 'h')
-	return 2;
+	return 2 + sep;
     else if (*wp->w_p_dym == 'd')
-	return 1;
+	return 1 + sep;
 # endif
     n = ptr2cells(s);
     /* Add one cell for a double-width character in the last column of the
@@ -1256,8 +1446,11 @@
     {
 	if (headp != NULL)
 	    *headp = 1;
-	return 3;
+	n = 3;
     }
+# ifdef FEAT_HEX
+    n += sep;
+# endif
     return n;
 }
 
@@ -1336,6 +1529,10 @@
 #endif
 	for (;;)
 	{
+#ifdef FEAT_HEX
+	    int		sep = 0;
+	    char_u	*line;
+#endif
 #ifdef FEAT_MBYTE
 	    head = 0;
 #endif
@@ -1383,6 +1580,42 @@
 		    incr = CHARSIZE(c);
 	    }
 
+#ifdef FEAT_HEX
+	    line = wp->w_buffer->b_ml.ml_line_ptr;
+	    if (STRLEN(line) > (ptr - line))
+	    {
+		if (wp->w_p_wrap && wp->w_onebuf_opt.cov_break > 0
+			&& ((ptr - line + 1) % wp->w_onebuf_opt.cov_break) == 0)
+		{
+		    int		numberextra;
+		    colnr_T	colmax;
+		    numberextra = win_col_off(curwin);
+		    colmax = (colnr_T)(W_WIDTH(curwin) - numberextra);
+		    if (vcol <= colmax)
+			incr = colmax - vcol;
+		    else
+		    {
+			numberextra = colmax;
+			colmax += win_col_off2(curwin);
+			incr = colmax - ((vcol - numberextra) % colmax);
+		    }
+		}
+		else
+		{
+		    int i = 0;
+
+		    while (wp->w_onebuf_opt.cov_sep[i])
+		    {
+			if (((ptr - line + 1) % wp->w_onebuf_opt.cov_sep[i]) == 0)
+			    ++sep;
+			++i;
+		    }
+		}
+	    }
+
+	    incr += sep;
+#endif
+
 	    if (posptr != NULL && ptr >= posptr) /* character at pos->col */
 		break;
 
diff -r e363850c5e8f -r e0da6e4047e4 src/option.c
--- a/src/option.c	Tue Feb 08 20:05:26 2011 +0100
+++ b/src/option.c	Thu Feb 10 22:54:29 2011 +0100
@@ -190,6 +190,9 @@
 #ifdef FEAT_ARABIC
 # define PV_ARAB	OPT_WIN(WV_ARAB)
 #endif
+#ifdef FEAT_HEX
+# define PV_COV		OPT_WIN(WV_COV)
+#endif
 #ifdef FEAT_DIFF
 # define PV_DIFF	OPT_WIN(WV_DIFF)
 #endif
@@ -790,6 +793,16 @@
     {"columns",	    "co",   P_NUM|P_NODEFAULT|P_NO_MKRC|P_VI_DEF|P_RCLR,
 			    (char_u *)&Columns, PV_NONE,
 			    {(char_u *)80L, (char_u *)0L} SCRIPTID_INIT},
+    {"columnview",  "cov",  P_STRING|P_ALLOCED|P_VIM|P_VI_DEF|
+						       P_RWIN|P_COMMA|P_NODUP,
+#ifdef FEAT_HEX
+			    (char_u *)VAR_WIN, PV_COV,
+			    {(char_u *)"", (char_u *)0L}
+#else
+			    (char_u *)NULL, PV_NONE,
+			    {(char_u *)0L, (char_u *)0L}
+#endif
+			    SCRIPTID_INIT},
     {"comments",    "com",  P_STRING|P_ALLOCED|P_VI_DEF|P_COMMA|P_NODUP,
 #ifdef FEAT_COMMENTS
 			    (char_u *)&p_com, PV_COM,
@@ -6893,6 +6906,40 @@
 	if (check_opt_strings(*varp, p_dym_values, FALSE) != OK)
 	    errmsg = e_invarg;
     }
+    /* 'columnview' */
+    else if (gvarp == &curwin->w_allbuf_opt.wo_cov)
+    {
+	int i = 0;
+	p = skipdigits(*varp);
+	while (*p == ',')
+	{
+	    ++i;
+	    ++p;
+	    if (i >= MAX_COV_SEP_COUNT || !VIM_ISDIGIT(*p) || *p < '1')
+	    {
+		errmsg = e_invarg;
+		break;
+	    }
+	    p = skipdigits(p);
+	}
+	if (*p != NUL)
+	    errmsg = e_invarg;
+	else if (errmsg == NULL)
+	{
+	    /* Parse the w_p_cov option and store it in wp. */
+	    winopt_T *w_opt;
+	    w_opt = (gvarp == varp)?&curwin->w_allbuf_opt:&curwin->w_onebuf_opt;
+	    i = 0;
+	    p = *varp;
+	    w_opt->cov_break = getdigits(&p);
+	    while (*p == ',')
+	    {
+		++p;
+		w_opt->cov_sep[i++] = getdigits(&p);
+	    }
+	    w_opt->cov_sep[i] = 0;
+	}
+    }
 #endif
 
     /* Options that are a list of flags. */
@@ -9640,6 +9687,7 @@
 #endif
 #ifdef FEAT_HEX
 	case PV_DYM:	return (char_u *)&(curwin->w_p_dym);
+	case PV_COV:	return (char_u *)&(curwin->w_p_cov);
 # ifdef FEAT_BYTEOFF
 	case PV_HNU:	return (char_u *)&(curwin->w_p_hnu);
 # endif
@@ -9860,6 +9908,9 @@
 #endif
 #ifdef FEAT_HEX
     to->wo_dym = vim_strsave(from->wo_dym);
+    to->wo_cov = vim_strsave(from->wo_cov);
+    mch_memmove(to->cov_sep, from->cov_sep, sizeof(to->cov_sep));
+    to->cov_break = from->cov_break;
 # ifdef FEAT_BYTEOFF
     to->wo_hnu = from->wo_hnu;
 # endif
@@ -9908,6 +9959,7 @@
 #endif
 #ifdef FEAT_HEX
     check_string_option(&wop->wo_dym);
+    check_string_option(&wop->wo_cov);
 #endif
 }
 
@@ -9941,6 +9993,7 @@
 #endif
 #ifdef FEAT_HEX
     clear_string_option(&wop->wo_dym);
+    clear_string_option(&wop->wo_cov);
 #endif
 }
 
diff -r e363850c5e8f -r e0da6e4047e4 src/option.h
--- a/src/option.h	Tue Feb 08 20:05:26 2011 +0100
+++ b/src/option.h	Thu Feb 10 22:54:29 2011 +0100
@@ -1040,6 +1040,9 @@
 #ifdef FEAT_CURSORBIND
     , WV_CRBIND
 #endif
+#ifdef FEAT_HEX
+    , WV_COV
+#endif
 #ifdef FEAT_DIFF
     , WV_DIFF
 #endif
diff -r e363850c5e8f -r e0da6e4047e4 src/screen.c
--- a/src/screen.c	Tue Feb 08 20:05:26 2011 +0100
+++ b/src/screen.c	Thu Feb 10 22:54:29 2011 +0100
@@ -2813,6 +2813,9 @@
 #if defined(LINE_ATTR)
     int		did_line_attr = 0;
 #endif
+#ifdef FEAT_HEX
+    int		cov_extra = 0;		/* separation size */
+#endif
 
     /* draw_state: items that are drawn in sequence: */
 #define WL_START	0		/* nothing done yet */
@@ -3900,6 +3903,15 @@
 		++p_extra;
 	    }
 	    --n_extra;
+
+#ifdef FEAT_HEX
+	    if (cov_extra)
+	    {
+		n_extra = cov_extra;
+		cov_extra = 0;
+		c_extra = ' ';
+	    }
+#endif
 	}
 	else
 	{
@@ -4275,7 +4287,11 @@
 		 * Found last space before word: check for line break.
 		 */
 		if (wp->w_p_lbr && vim_isbreak(c) && !vim_isbreak(*ptr)
-							     && !wp->w_p_list)
+							     && !wp->w_p_list
+#ifdef FEAT_HEX
+							     && *wp->w_p_cov == NUL
+#endif
+							     )
 		{
 		    n_extra = win_lbr_chartabsize(wp, ptr - (
 # ifdef FEAT_MBYTE
@@ -4593,6 +4609,51 @@
 		is_concealing = FALSE;
 	    }
 #endif /* FEAT_CONCEAL */
+
+#ifdef FEAT_HEX
+	    /* Add sperators at the locations listed in 'columnview' */
+	    if (ptr[0] != NUL)
+	    {
+		if ((ptr - line) > 0
+			&& wp->w_p_wrap && wp->w_onebuf_opt.cov_break != 0
+			&& ((ptr - line) % wp->w_onebuf_opt.cov_break) == 0)
+		{
+		    int	    numberextra;
+		    colnr_T colmax;
+		    numberextra = 0;//win_col_off(curwin);
+		    colmax = (colnr_T)(W_WIDTH(curwin) - numberextra);
+		    if (col <= colmax)
+			cov_extra = colmax - col;
+		    else
+		    {
+			numberextra = colmax;
+			colmax += win_col_off2(curwin);
+			cov_extra = colmax - ((col - numberextra) % colmax);
+		    }
+		    cov_extra -= n_extra + 1;
+		}
+		else
+		{
+		    int i = 0;
+
+		    cov_extra = 0;
+
+		    while (wp->w_onebuf_opt.cov_sep[i])
+		    {
+			if (((ptr - line) % wp->w_onebuf_opt.cov_sep[i]) == 0)
+			    ++cov_extra;
+			++i;
+		    }
+		}
+
+		if (n_extra == 0)
+		{
+		    n_extra = cov_extra;
+		    cov_extra = 0;
+		    c_extra = ' ';
+		}
+	    }
+#endif
 	}
 
 #ifdef FEAT_CONCEAL
diff -r e363850c5e8f -r e0da6e4047e4 src/structs.h
--- a/src/structs.h	Tue Feb 08 20:05:26 2011 +0100
+++ b/src/structs.h	Thu Feb 10 22:54:29 2011 +0100
@@ -228,6 +228,12 @@
 #ifdef FEAT_HEX
     char_u	*wo_dym;
 # define w_p_dym w_onebuf_opt.wo_dym	/* 'displaymode' */
+# define MAX_COV_SEP_COUNT 128		/* it would be insane to have this much
+					   seperations */
+    char_u	*wo_cov;
+# define w_p_cov w_onebuf_opt.wo_cov	/* 'columnview' */
+    long	cov_sep[MAX_COV_SEP_COUNT]; /* Parsed version of w_p_cov */
+    long	cov_break;		/* Parsed version of w_p_cov */
 # ifdef FEAT_BYTEOFF
     int		wo_hnu;
 #  define w_p_hnu w_onebuf_opt.wo_hnu	/* 'hexnumber' */
