ref: 9842b0ae2fd64c678b545ca71f9c34b7afba87c5
parent: e89b9646cd52f1d97c84db52406636ee1bb396e9
author: phil9 <telephil9@gmail.com>
date: Sat Jun 1 11:39:42 EDT 2024
add a style configuration directive to spit files spit files now accept, before any other declarations, a new @style directive to configure the different style elements (fonts included). The syntax is of the form: @style[KEY]\s*=\s*VALUE The possible keys are (see style.h for their use and values): - title.font - title.size - text.font - text.size - fixed.font - fixed.size - margin - padding - color.bg - color.fg - color.quotebg - color.quoteborder - color.codebg - color.codeborder All have default values except for title.font which must be set. If text.font and fixed.font are not specified they will default to using title.font.
--- a/sample.spit
+++ b/sample.spit
@@ -1,4 +1,7 @@
; Demonstration of spit capabilities
+@style[title.font] = /lib/font/ttf/DejaVuSans.ttf
+@style[fixed.font] = /lib/font/ttf/DejaVuSans-Mono.ttf
+
# A sample presentation
spit is a simple presentation tool for plan9.
spit presentations are simple markdown-like files.
--- a/spit.c
+++ b/spit.c
@@ -4,8 +4,11 @@
Mousectl *mc;
Keyboardctl *kc;
Image *cols[Ncols];
+char *ftitlename;
Sfont *ftitle;
+char *ftextname;
Sfont *ftext;
+char *ffixedname;
Sfont *ffixed;
Sdopts opts = {.prefilter = 0, .gamma = 1.0 };
int fullscreen;
@@ -39,7 +42,7 @@
error(char *f, int l, char *m)
{
fprint(2, "error: %s at %s:%d\n", m, f, l);
- exits("error");
+ threadexitsall("error");
}
Image*
@@ -189,7 +192,118 @@
return p;
}
+char*
+skipws(char *s)
+{
+ while(*s == ' ' || *s == '\t')
+ ++s;
+ return s;
+}
+
+ulong
+estrtoul(char *f, int line, char *s)
+{
+ char *e;
+ ulong c;
+
+ c = strtoul(s, &e, 16);
+ if(e == s || e == nil)
+ error(f, line, "invalid number");
+ return (c << 8) | 0xff;
+}
+
void
+parsestyle(char *f, int line, char *s)
+{
+ char k[32] = {0}, *p;
+
+ s += 6; /* skip '@style' */
+ if(s[0] != '[')
+ error(f, line, "expected '[' character in style declaration");
+ p = strchr(s, ']');
+ if(p == nil)
+ error(f, line, "expected ']' character in style declaration");
+ if(p == s+1)
+ error(f, line, "empty style declaration");
+ if(p-s >= 32)
+ error(f, line, "invalid key in style declaration");
+ strncpy(k, s+1, p-s-1);
+ s = skipws(p+1);
+ if(*s != '=')
+ error(f, line, "expected '=' character in style declaration");
+ s = skipws(s+1);
+ if(*s == 0)
+ error(f, line, "empty style value");
+ if(strcmp(k, "margin") == 0){
+ margin = atoi(s);
+ if(margin == 0) error(f, line, "invalid 'margin' value");
+ }else if(strcmp(k, "padding") == 0){
+ padding = atoi(s);
+ if(padding == 0) error(f, line, "invalid 'padding' value");
+ }else if(strcmp(k, "lineheight") == 0){
+ lineheight = atof(s);
+ if(lineheight < 1.0) error(f, line, "invalid 'lineheight' value");
+ }else if(strcmp(k, "color.bg") == 0)
+ coldefs[Cbg] = estrtoul(f, line, s);
+ else if(strcmp(k, "color.fg") == 0)
+ coldefs[Cfg] = estrtoul(f, line, s);
+ else if(strcmp(k, "color.quotebg") == 0)
+ coldefs[Cqbg] = estrtoul(f, line, s);
+ else if(strcmp(k, "color.quoteborder") == 0)
+ coldefs[Cqbord] = estrtoul(f, line, s);
+ else if(strcmp(k, "color.codebg") == 0)
+ coldefs[Ccbg] = estrtoul(f, line, s);
+ else if(strcmp(k, "color.codeborder") == 0)
+ coldefs[Ccbord] = estrtoul(f, line, s);
+ else if(strcmp(k, "title.font") == 0)
+ ftitlename = strdup(s);
+ else if(strcmp(k, "title.size") == 0)
+ ftitlesz = atof(s);
+ else if(strcmp(k, "text.font") == 0)
+ ftextname = strdup(s);
+ else if(strcmp(k, "text.size") == 0)
+ ftextsz = atof(s);
+ else if(strcmp(k, "fixed.font") == 0)
+ ffixedname = strdup(s);
+ else if(strcmp(k, "fixed.size") == 0)
+ ffixedsz = atof(s);
+ else
+ error(f, line, "unknown style key");
+}
+
+void
+initimages(void)
+{
+ Point p[4];
+
+ bol = allocimage(display, Rect(0, 0, ftextsz, ftextsz), screen->chan, 0, coldefs[Cbg]);
+ p[0] = Pt(0.25*ftextsz, 0.25*ftextsz);
+ p[1] = Pt(0.25*ftextsz, 0.75*Dy(bol->r));
+ p[2] = Pt(0.75*ftextsz, 0.50*Dy(bol->r));
+ p[3] = p[0];
+ fillpoly(bol, p, 4, 0, cols[Cfg], ZP);
+ bullet = allocimage(display, Rect(0, 0, ftextsz, ftextsz), screen->chan, 0, coldefs[Cbg]);
+ fillellipse(bullet, Pt(0.5*ftextsz, 0.5*ftextsz), 0.15*ftextsz, 0.15*ftextsz, cols[Cfg], ZP);
+}
+
+void
+loadstyle(char *f)
+{
+ int i;
+
+ if(ftitlename == nil){
+ fprint(2, "%s: no title font defined", f);
+ threadexitsall("missing font");
+ }
+ for(i = 0; i < Ncols; i++)
+ cols[i] = ealloccol(coldefs[i]);
+ ftitle = loadsfont(ftitlename, ftitlesz);
+ ftext = loadsfont(ftextname ? ftextname : ftitlename, ftextsz);
+ ffixed = loadsfont(ffixedname ? ffixedname : ftitlename, ffixedsz);
+ initimages();
+}
+
+void
render(char *f)
{
enum { Sstart, Scomment, Scontent, Slist, Squote, Scode };
@@ -215,11 +329,18 @@
Again:
switch(s){
case Sstart:
- if(l[0] == ';'){
+ if(l[0] == ';' || l[0] == 0){
free(l);
continue;
}
+ if(strncmp(l, "@style", 6) == 0){
+ parsestyle(f, ln, l);
+ free(l);
+ continue;
+ }
if(l[0] != '#') error(f, ln, "expected title line");
+ if(nslides == -1) /* all style parsed but not slide rendered yet */
+ loadstyle(f);
Title:
p = Pt(margin, margin);
b = addslide();
@@ -352,36 +473,9 @@
}
void
-initstyle(char *tname, char *fname)
-{
- int i;
-
- for(i = 0; i < Ncols; i++)
- cols[i] = ealloccol(coldefs[i]);
- ftitle = loadsfont(tname, ftitlesz);
- ftext = loadsfont(tname, ftextsz);
- ffixed = loadsfont(fname ? fname : tname, ffixedsz);
-}
-
-void
-initimages(void)
-{
- Point p[4];
-
- bol = allocimage(display, Rect(0, 0, ftextsz, ftextsz), screen->chan, 0, coldefs[Cbg]);
- p[0] = Pt(0.25*ftextsz, 0.25*ftextsz);
- p[1] = Pt(0.25*ftextsz, 0.75*Dy(bol->r));
- p[2] = Pt(0.75*ftextsz, 0.50*Dy(bol->r));
- p[3] = p[0];
- fillpoly(bol, p, 4, 0, cols[Cfg], ZP);
- bullet = allocimage(display, Rect(0, 0, ftextsz, ftextsz), screen->chan, 0, coldefs[Cbg]);
- fillellipse(bullet, Pt(0.5*ftextsz, 0.5*ftextsz), 0.15*ftextsz, 0.15*ftextsz, cols[Cfg], ZP);
-}
-
-void
usage(void)
{
- fprint(2, "%s [-n] [-f font] [-F fixedfont]<filename>\n", argv0);
+ fprint(2, "%s [-n] <filename>\n", argv0);
exits("usage");
}
@@ -389,7 +483,7 @@
threadmain(int argc, char **argv)
{
enum { Emouse, Eresize, Ekeyboard };
- char *f, *tname, *fname;
+ char *f;
Mouse m;
Rune k;
Alt alts[] = {
@@ -399,25 +493,16 @@
{ nil, nil, CHANEND },
};
- tname = nil;
- fname = nil;
+ ftitlename = nil;
+ ftextname = nil;
+ ffixedname = nil;
ARGBEGIN{
case 'n':
nodraw = 1;
break;
- case 'f':
- tname = EARGF(usage());
- break;
- case 'F':
- fname = EARGF(usage());
- break;
default:
usage();
}ARGEND;
- if(tname == nil){
- fprint(2, "missing -f argument\n");
- usage();
- }
if((f = *argv) == nil){
fprint(2, "missing filename\n");
usage();
@@ -436,8 +521,6 @@
memimageinit();
fullscreen = 0;
screenr = screen->r;
- initstyle(tname, fname);
- initimages();
render(f);
if(nodraw){
barf();