Blob
- Date:
- Message:
- 9term, mc: conspire to handle hidpi displays 9term now uses the low bit of ws.ws_ypixel to signal whether this is a hidpi display, and mc adjusts the font it uses for columnation accordingly. Makes 'lc' work right on hidpi displays. Change-Id: I52928871ffb7f4c6fd6722f3d59f1836379148c6 Reviewed-on: https://plan9port-review.googlesource.com/2760 Reviewed-by: Russ Cox <rsc@swtch.com>
- Actions:
- History | Blame | Raw File
1 /*2 * mc - columnate3 *4 * mc[-][-LINEWIDTH][-t][file...]5 * - causes break on colon6 * -LINEWIDTH sets width of line in which to columnate(default 80)7 * -t suppresses expanding multiple blanks into tabs8 *9 */10 #include <u.h>11 #include <sys/ioctl.h>12 #include <sys/termios.h>13 #include <libc.h>14 #include <draw.h>15 #include <bio.h>16 #include <fcall.h>17 #include <9pclient.h>18 #include <thread.h>20 #define WIDTH 8021 #define TAB 422 #define WORD_ALLOC_QUANTA 102423 #define ALLOC_QUANTA 409625 int wordsize(Rune*, int);26 int nexttab(int);28 int tabwid;29 int mintab = 1;30 int linewidth=WIDTH;31 int colonflag=0;32 int tabflag=0; /* -t flag turned off forever, except in acme */33 Rune *cbuf, *cbufp;34 Rune **word;35 int maxwidth=0;36 int nalloc=ALLOC_QUANTA;37 int nwalloc=WORD_ALLOC_QUANTA;38 int nchars=0;39 int nwords=0;40 Biobuf bin;41 Biobuf bout;43 void getwidth(void), readbuf(int), error(char *);44 void scanwords(void), columnate(void), morechars(void);46 void47 threadmain(int argc, char *argv[])48 {49 int i;50 int lineset;51 int ifd;53 lineset = 0;54 Binit(&bout, 1, OWRITE);55 while(argc > 1 && argv[1][0] == '-'){56 --argc; argv++;57 switch(argv[0][1]){58 case '\0':59 colonflag = 1;60 break;61 case 't':62 tabflag = 0;63 break;64 default:65 linewidth = atoi(&argv[0][1]);66 if(linewidth <= 1)67 linewidth = WIDTH;68 lineset = 1;69 break;70 }71 }72 if(lineset == 0)73 getwidth();74 cbuf = cbufp = malloc(ALLOC_QUANTA*(sizeof *cbuf));75 word = malloc(WORD_ALLOC_QUANTA*(sizeof *word));76 if(word == 0 || cbuf == 0)77 error("out of memory");78 if(argc == 1)79 readbuf(0);80 else{81 for(i = 1; i < argc; i++){82 if((ifd = open(*++argv, OREAD)) == -1)83 fprint(2, "mc: can't open %s (%r)\n", *argv);84 else{85 readbuf(ifd);86 Bflush(&bin);87 close(ifd);88 }89 }90 }91 columnate();92 Bflush(&bout);93 threadexitsall(0);94 }95 void96 error(char *s)97 {98 fprint(2, "mc: %s\n", s);99 threadexitsall(s);100 }101 void102 readbuf(int fd)103 {104 int lastwascolon = 0;105 long c;106 int linesiz = 0;108 Binit(&bin, fd, OREAD);109 do{110 if(nchars++ >= nalloc)111 morechars();112 *cbufp++ = c = Bgetrune(&bin);113 linesiz++;114 if(c == '\t') {115 cbufp[-1] = L' ';116 while(linesiz%TAB != 0) {117 if(nchars++ >= nalloc)118 morechars();119 *cbufp++ = L' ';120 linesiz++;121 }122 }123 if(colonflag && c == ':')124 lastwascolon++;125 else if(lastwascolon){126 if(c == '\n'){127 --nchars; /* skip newline */128 *cbufp = L'\0';129 while(nchars > 0 && cbuf[--nchars] != '\n')130 ;131 if(nchars)132 nchars++;133 columnate();134 if (nchars)135 Bputc(&bout, '\n');136 Bprint(&bout, "%S", cbuf+nchars);137 nchars = 0;138 cbufp = cbuf;139 }140 lastwascolon = 0;141 }142 if(c == '\n')143 linesiz = 0;144 }while(c >= 0);145 }146 void147 scanwords(void)148 {149 Rune *p, *q;150 int i, w;152 nwords=0;153 maxwidth=0;154 for(p = q = cbuf, i = 0; i < nchars; i++){155 if(*p++ == L'\n'){156 if(nwords >= nwalloc){157 nwalloc += WORD_ALLOC_QUANTA;158 if((word = realloc(word, nwalloc*sizeof(*word)))==0)159 error("out of memory");160 }161 word[nwords++] = q;162 p[-1] = L'\0';163 w = wordsize(q, p-q-1);164 if(w > maxwidth)165 maxwidth = w;166 q = p;167 }168 }169 }171 void172 columnate(void)173 {174 int i, j;175 int words_per_line;176 int nlines;177 int col;178 int endcol;181 scanwords();182 if(nwords==0)183 return;184 maxwidth = nexttab(maxwidth+mintab-1);185 words_per_line = linewidth/maxwidth;186 if(words_per_line <= 0)187 words_per_line = 1;188 nlines=(nwords+words_per_line-1)/words_per_line;189 for(i = 0; i < nlines; i++){190 col = endcol = 0;191 for(j = i; j < nwords; j += nlines){192 endcol += maxwidth;193 Bprint(&bout, "%S", word[j]);194 col += wordsize(word[j], runestrlen(word[j]));195 if(j+nlines < nwords){196 if(tabflag) {197 while(col < endcol){198 Bputc(&bout, '\t');199 col = nexttab(col);200 }201 }else{202 while(col < endcol){203 Bputc(&bout, ' ');204 col++;205 }206 }207 }208 }209 Bputc(&bout, '\n');210 }211 }213 int214 wordsize(Rune *w, int nw)215 {216 if(nw < 0)217 abort();218 if(font)219 return runestringnwidth(font, w, nw);220 return nw;221 }223 int224 nexttab(int col)225 {226 if(tabwid){227 col += tabwid;228 col -= col%tabwid;229 return col;230 }231 return col+1;232 }234 void235 morechars(void)236 {237 nalloc += ALLOC_QUANTA;238 if((cbuf = realloc(cbuf, nalloc*sizeof(*cbuf))) == 0)239 error("out of memory");240 cbufp = cbuf+nchars-1;241 }243 /*244 * These routines discover the width of the display.245 * It takes some work. If we do the easy calls to the246 * draw library, the screen flashes due to repainting247 * when mc exits.248 */249 int250 windowrect(struct winsize *ws)251 {252 int tty;254 if((tty = open("/dev/tty", OWRITE)) < 0)255 tty = 1;257 if(ioctl(tty, TIOCGWINSZ, ws) < 0){258 if(tty != 1)259 close(tty);260 return -1;261 }262 if(tty != 1)263 close(tty);264 return 0;265 }267 void268 getwidth(void)269 {270 CFsys *fs;271 char buf[500], *p, *q, *f[10];272 int fd, n, nf;273 struct winsize ws;274 Font *f1;276 if((p = getenv("winid")) != nil){277 fs = nsmount("acme", "");278 if(fs == nil)279 return;280 snprint(buf, sizeof buf, "acme/%d/ctl", atoi(p));281 if((fd = fsopenfd(fs, buf, OREAD)) < 0)282 return;283 if((n=readn(fd, buf, sizeof buf-1)) <= 0)284 return;285 buf[n] = 0;286 if((nf=tokenize(buf, f, nelem(f))) < 7)287 return;288 tabwid = 0;289 if(nf >= 8 && (tabwid = atoi(f[7])) == 0)290 return;291 if((font = openfont(nil, f[6])) == nil)292 return;293 mintab = stringwidth(font, "0");294 if(tabwid == 0)295 tabwid = mintab*4;296 linewidth = atoi(f[5]);297 tabflag = 1;298 return;299 }301 if((p = getenv("termprog")) != nil && strcmp(p, "9term") == 0)302 if((p = getenv("font")) != nil)303 font = openfont(nil, p);305 if(windowrect(&ws) < 0)306 return;307 if(ws.ws_xpixel == 0)308 font = nil;309 if(font){310 // 9term leaves "is this a hidpi display" in the low bit of the ypixel height.311 if(ws.ws_ypixel&1) {312 // need hidpi font.313 // loadhifpi creates a font that crashes in stringwidth,314 // for reasons i don't understand.315 // do it ourselves316 p = getenv("font");317 q = strchr(p, ',');318 f1 = nil;319 if(q != nil)320 f1 = openfont(nil, q+1);321 if(f1 != nil)322 font = f1;323 else324 ws.ws_xpixel /= 2;325 }326 mintab = stringwidth(font, "0");327 if((p = getenv("tabstop")) != nil)328 tabwid = atoi(p)*mintab;329 else330 tabwid = 4*mintab;331 tabflag = 1;332 linewidth = ws.ws_xpixel;333 }else334 linewidth = ws.ws_col;335 }