Skip to content

Commit

Permalink
Add :show command to display special symbols for whitespaces
Browse files Browse the repository at this point in the history
Enable/disable by setting to 0/1 respectively:

 :set show spaces=0 tabs=0 newlines=1
  • Loading branch information
martanne committed Jul 3, 2015
1 parent 860ad58 commit 87c7258
Show file tree
Hide file tree
Showing 6 changed files with 149 additions and 17 deletions.
19 changes: 19 additions & 0 deletions config.def.h
Original file line number Diff line number Diff line change
Expand Up @@ -827,6 +827,11 @@ enum {
COLOR_COMMENT = COLOR_SYNTAX7,
COLOR_IDENTIFIER = COLOR_SYNTAX8,
COLOR_TYPE = COLOR_SYNTAX9,
COLOR_WHITESPACE = COLOR_COMMENT,
COLOR_SPACES = COLOR_WHITESPACE,
COLOR_TABS = COLOR_WHITESPACE,
COLOR_EOL = COLOR_WHITESPACE,
COLOR_EOF = COLOR_WHITESPACE,
};

static Color colors[] = {
Expand Down Expand Up @@ -894,6 +899,12 @@ static Color colors[] = {
&colors[COLOR_PREPROCESSOR], \
}

#define SYNTAX_SPACES { "\xC2\xB7", &colors[COLOR_SPACES] }
#define SYNTAX_TABS { "\xE2\x96\xB6", &colors[COLOR_TABS] }
#define SYNTAX_TABS_FILL { " ", &colors[COLOR_TABS] }
#define SYNTAX_EOL { "\xE2\x8F\x8E", &colors[COLOR_EOL] }
#define SYNTAX_EOF { "~", &colors[COLOR_EOF] }

/* these rules are applied top to bottom, first match wins. Therefore more 'greedy'
* rules such as for comments should be the first entries.
*
Expand All @@ -905,8 +916,16 @@ static Syntax syntaxes[] = {{
.settings = (const char*[]){
"set number",
"set autoindent",
"set show spaces=0 tabs=1 newlines=1",
NULL
},
.symbols = {
SYNTAX_SPACES,
SYNTAX_TABS,
SYNTAX_TABS_FILL,
SYNTAX_EOL,
SYNTAX_EOF,
},
.rules = {
SYNTAX_MULTILINE_COMMENT,
SYNTAX_SINGLE_LINE_COMMENT,
Expand Down
15 changes: 15 additions & 0 deletions syntax.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,27 @@ typedef struct {
regex_t regex; /* compiled form of the above rule */
} SyntaxRule;

typedef struct {
char *symbol;
Color *color;
} SyntaxSymbol;

enum {
SYNTAX_SYMBOL_SPACE,
SYNTAX_SYMBOL_TAB,
SYNTAX_SYMBOL_TAB_FILL,
SYNTAX_SYMBOL_EOL,
SYNTAX_SYMBOL_EOF,
SYNTAX_SYMBOL_LAST,
};

typedef struct Syntax Syntax;
struct Syntax { /* a syntax definition */
char *name; /* syntax name */
char *file; /* apply to files matching this regex */
regex_t file_regex; /* compiled file name regex */
const char **settings;/* settings associated with this file type */
SyntaxSymbol symbols[SYNTAX_SYMBOL_LAST]; /* symbols for white space handling */
SyntaxRule rules[24]; /* all rules for this file type */
};

Expand Down
4 changes: 3 additions & 1 deletion ui-curses.c
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,7 @@ static void ui_window_draw_sidebar(UiCursesWin *win, const Line *line) {
size_t cursor_lineno = view_cursor_getpos(win->view).line;
werase(win->winside);
for (const Line *l = line; l; l = l->next, i++) {
if (l->lineno != prev_lineno) {
if (l->lineno && l->lineno != prev_lineno) {
if (win->options & UI_OPTION_LINE_NUMBERS_ABSOLUTE) {
mvwprintw(win->winside, i, 0, "%*u", sidebar_width-1, l->lineno);
} else if (win->options & UI_OPTION_LINE_NUMBERS_RELATIVE) {
Expand Down Expand Up @@ -376,6 +376,8 @@ static void ui_window_draw_text(UiWin *w, const Line *line) {
wattrset(win->win, l->cells[x].attr);
waddstr(win->win, l->cells[x].data);
}
if (l->width != win->width - win->sidebar_width)
waddstr(win->win, "\n");
}
wclrtoeol(win->win);
}
Expand Down
94 changes: 78 additions & 16 deletions view.c
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,26 @@ struct View { /* viewable area, showing part of a file */
Line *line; /* used while drawing view content, line where next char will be drawn */
int col; /* used while drawing view content, column where next char will be drawn */
Syntax *syntax; /* syntax highlighting definitions for this view or NULL */
SyntaxSymbol *symbols[SYNTAX_SYMBOL_LAST]; /* symbols to use for white spaces etc */
int tabwidth; /* how many spaces should be used to display a tab character */
};

static SyntaxSymbol symbols_none[] = {
{ " " }, /* spaces */
{ " " }, /* tab first cell */
{ " " }, /* tab remaining cells */
{ "" }, /* eol */
{ "~" }, /* eof */
};

static SyntaxSymbol symbols_default[] = {
{ "\xC2\xB7" }, /* spaces */
{ "\xE2\x96\xB6" }, /* tab first cell */
{ " " }, /* tab remaining cells */
{ "\xE2\x8F\x8E" }, /* eol */
{ "~" }, /* eof */
};

static void view_clear(View *view);
static bool view_addch(View *view, Cell *cell);
static size_t view_cursor_update(View *view);
Expand Down Expand Up @@ -134,6 +151,8 @@ static bool view_addch(View *view, Cell *cell) {

switch (cell->data[0]) {
case '\t':
cell->istab = true;
cell->width = 1;
width = view->tabwidth - (view->col % view->tabwidth);
for (int w = 0; w < width; w++) {
if (view->col + 1 > view->width) {
Expand All @@ -143,23 +162,18 @@ static bool view_addch(View *view, Cell *cell) {
return false;
view->line->lineno = lineno;
}
if (w == 0) {
/* first cell of a tab has a length of 1 */
view->line->cells[view->col].len = cell->len;
view->line->len += cell->len;
} else {
/* all remaining ones have a lenght of zero */
view->line->cells[view->col].len = 0;
}
/* but all are marked as part of a tabstop */
view->line->cells[view->col].width = 1;
view->line->cells[view->col].data[0] = ' ';
view->line->cells[view->col].data[1] = '\0';
view->line->cells[view->col].istab = true;
view->line->cells[view->col].attr = cell->attr;
view->line->width++;

cell->len = w == 0 ? 1 : 0;
int t = w == 0 ? SYNTAX_SYMBOL_TAB : SYNTAX_SYMBOL_TAB_FILL;
strncpy(cell->data, view->symbols[t]->symbol, sizeof(cell->data));
if (view->symbols[t]->color)
cell->attr = view->symbols[t]->color->attr;
view->line->cells[view->col] = *cell;
view->line->len += cell->len;
view->line->width += cell->width;
view->col++;
}
cell->len = 1;
return true;
case '\n':
cell->width = 1;
Expand All @@ -170,6 +184,11 @@ static bool view_addch(View *view, Cell *cell) {
return false;
view->line->lineno = lineno;
}

strncpy(cell->data, view->symbols[SYNTAX_SYMBOL_EOL]->symbol, sizeof(cell->data));
if (view->symbols[SYNTAX_SYMBOL_EOL]->color)
cell->attr = view->symbols[SYNTAX_SYMBOL_EOL]->color->attr;

view->line->cells[view->col] = *cell;
view->line->len += cell->len;
view->line->width += cell->width;
Expand All @@ -193,6 +212,12 @@ static bool view_addch(View *view, Cell *cell) {
};
}

if (cell->data[0] == ' ') {
strncpy(cell->data, view->symbols[SYNTAX_SYMBOL_SPACE]->symbol, sizeof(cell->data));
if (view->symbols[SYNTAX_SYMBOL_SPACE]->color)
cell->attr = view->symbols[SYNTAX_SYMBOL_SPACE]->color->attr;
}

if (view->col + cell->width > view->width) {
for (int i = view->col; i < view->width; i++)
view->line->cells[i] = empty;
Expand Down Expand Up @@ -452,7 +477,15 @@ void view_draw(View *view) {
/* set end of vieviewg region */
view->end = pos;
view->lastline = view->line ? view->line : view->bottomline;
view->lastline->next = NULL;

for (Line *l = view->lastline->next; l; l = l->next) {
strncpy(l->cells[0].data, view->symbols[SYNTAX_SYMBOL_EOF]->symbol, sizeof(l->cells[0].data));
if (view->symbols[SYNTAX_SYMBOL_EOF]->color)
l->cells[0].attr =view->symbols[SYNTAX_SYMBOL_EOF]->color->attr;
l->width = 1;
l->len = 0;
}

view_cursor_sync(view);
if (view->ui)
view->ui->draw_text(view->ui, view->topline);
Expand Down Expand Up @@ -505,6 +538,7 @@ View *view_new(Text *text, ViewEvent *events) {
view->text = text;
view->events = events;
view->tabwidth = 8;
view_symbols_set(view, 0);

if (!view_resize(view, 1, 1)) {
view_free(view);
Expand Down Expand Up @@ -776,12 +810,40 @@ void view_selection_start(View *view) {

void view_syntax_set(View *view, Syntax *syntax) {
view->syntax = syntax;
for (int i = 0; i < LENGTH(view->symbols); i++) {
if (syntax && syntax->symbols[i].symbol)
view->symbols[i] = &syntax->symbols[i];
else
view->symbols[i] = &symbols_none[i];
}
}

Syntax *view_syntax_get(View *view) {
return view->syntax;
}

void view_symbols_set(View *view, int flags) {
for (int i = 0; i < LENGTH(view->symbols); i++) {
if (flags & (1 << i)) {
if (view->syntax && view->syntax->symbols[i].symbol)
view->symbols[i] = &view->syntax->symbols[i];
else
view->symbols[i] = &symbols_default[i];
} else {
view->symbols[i] = &symbols_none[i];
}
}
}

int view_symbols_get(View *view) {
int flags = 0;
for (int i = 0; i < LENGTH(view->symbols); i++) {
if (view->symbols[i] != &symbols_none[i])
flags |= (1 << i);
}
return flags;
}

size_t view_screenline_goto(View *view, int n) {
size_t pos = view->start;
for (Line *line = view->topline; --n > 0 && line != view->lastline; line = line->next)
Expand Down
2 changes: 2 additions & 0 deletions view.h
Original file line number Diff line number Diff line change
Expand Up @@ -115,5 +115,7 @@ bool view_viewport_down(View *view, int n);
/* associate a set of syntax highlighting rules to this window. */
void view_syntax_set(View*, Syntax*);
Syntax *view_syntax_get(View*);
void view_symbols_set(View*, int flags);
int view_symbols_get(View*);

#endif
32 changes: 32 additions & 0 deletions vis.c
Original file line number Diff line number Diff line change
Expand Up @@ -1339,6 +1339,7 @@ static bool cmd_set(Filerange *range, enum CmdOpt cmdopt, const char *argv[]) {
OPTION_EXPANDTAB,
OPTION_TABWIDTH,
OPTION_SYNTAX,
OPTION_SHOW,
OPTION_NUMBER,
OPTION_NUMBER_RELATIVE,
};
Expand All @@ -1349,6 +1350,7 @@ static bool cmd_set(Filerange *range, enum CmdOpt cmdopt, const char *argv[]) {
[OPTION_EXPANDTAB] = { { "expandtab", "et" }, OPTION_TYPE_BOOL },
[OPTION_TABWIDTH] = { { "tabwidth", "tw" }, OPTION_TYPE_NUMBER },
[OPTION_SYNTAX] = { { "syntax" }, OPTION_TYPE_STRING, true },
[OPTION_SHOW] = { { "show" }, OPTION_TYPE_STRING },
[OPTION_NUMBER] = { { "numbers", "nu" }, OPTION_TYPE_BOOL },
[OPTION_NUMBER_RELATIVE] = { { "relativenumbers", "rnu" }, OPTION_TYPE_BOOL },
};
Expand Down Expand Up @@ -1448,6 +1450,36 @@ static bool cmd_set(Filerange *range, enum CmdOpt cmdopt, const char *argv[]) {
else
editor_info_show(vis, "Unknown syntax definition: `%s'", argv[2]);
break;
case OPTION_SHOW:
if (!argv[2]) {
editor_info_show(vis, "Expecting: spaces, tabs, newlines");
return false;
}
char *keys[] = { "spaces", "tabs", "newlines" };
int values[] = {
1 << SYNTAX_SYMBOL_SPACE,
(1 << SYNTAX_SYMBOL_TAB)|(1 << SYNTAX_SYMBOL_TAB_FILL),
1 << SYNTAX_SYMBOL_EOL
};
int flags = view_symbols_get(vis->win->view);
for (const char **args = &argv[2]; *args; args++) {
for (int i = 0; i < LENGTH(keys); i++) {
if (strcmp(*args, keys[i]) == 0) {
flags |= values[i];
} else if (strstr(*args, keys[i]) == *args) {
bool show;
const char *v = *args + strlen(keys[i]);
if (*v == '=' && parse_bool(v+1, &show)) {
if (show)
flags |= values[i];
else
flags &= ~values[i];
}
}
}
}
view_symbols_set(vis->win->view, flags);
break;
case OPTION_NUMBER:
editor_window_options(vis->win, arg.b ? UI_OPTION_LINE_NUMBERS_ABSOLUTE :
UI_OPTION_LINE_NUMBERS_NONE);
Expand Down

0 comments on commit 87c7258

Please sign in to comment.