9fans.net/go@v0.0.7/cmd/acme/internal/dump/rows1.go (about) 1 // #include <u.h> 2 // #include <libc.h> 3 // #include <draw.h> 4 // #include <thread.h> 5 // #include <cursor.h> 6 // #include <mouse.h> 7 // #include <keyboard.h> 8 // #include <frame.h> 9 // #include <fcall.h> 10 // #include <bio.h> 11 // #include <plumb.h> 12 // #include <libsec.h> 13 // #include "dat.h" 14 // #include "fns.h" 15 16 package dump 17 18 import ( 19 "bufio" 20 "fmt" 21 "io/ioutil" 22 "os" 23 "strconv" 24 "unicode/utf8" 25 26 "9fans.net/go/cmd/acme/internal/adraw" 27 "9fans.net/go/cmd/acme/internal/alog" 28 "9fans.net/go/cmd/acme/internal/bufs" 29 "9fans.net/go/cmd/acme/internal/fileload" 30 "9fans.net/go/cmd/acme/internal/ui" 31 "9fans.net/go/cmd/acme/internal/util" 32 "9fans.net/go/cmd/acme/internal/wind" 33 "9fans.net/go/draw" 34 ) 35 36 var Get = func(*wind.Text) {} 37 var Run = func(string, []rune) {} 38 var Home = "" 39 var OnNewWindow = func(*wind.Window) {} 40 41 func Dump(row *wind.Row, file *string) { 42 if len(row.Col) == 0 { 43 return 44 } 45 // defer fbuffree(buf) 46 if file == nil { 47 if Home == "" { 48 alog.Printf("can't find file for dump: $home not defined\n") 49 return 50 } 51 s := fmt.Sprintf("%s/acme.dump", Home) 52 file = &s 53 } 54 f, err := os.Create(*file) 55 if err != nil { 56 alog.Printf("can't open %s: %v\n", *file, err) 57 return 58 } 59 b := bufio.NewWriter(f) 60 r := bufs.AllocRunes() 61 fmt.Fprintf(b, "%s\n", ui.Wdir) 62 fmt.Fprintf(b, "%s\n", adraw.FontNames[0]) 63 fmt.Fprintf(b, "%s\n", adraw.FontNames[1]) 64 var i int 65 var c *wind.Column 66 for i = 0; i < len(row.Col); i++ { 67 c = row.Col[i] 68 fmt.Fprintf(b, "%11.7f", 100.0*float64(c.R.Min.X-row.R.Min.X)/float64(row.R.Dx())) 69 if i == len(row.Col)-1 { 70 b.WriteByte('\n') 71 } else { 72 b.WriteByte(' ') 73 } 74 } 75 dumpid := make(map[*wind.File]int) 76 m := util.Min(bufs.RuneLen, row.Tag.Len()) 77 row.Tag.File.Read(0, r[:m]) 78 n := 0 79 for n < m && r[n] != '\n' { 80 n++ 81 } 82 fmt.Fprintf(b, "w %s\n", string(r[:n])) 83 for i = 0; i < len(row.Col); i++ { 84 c = row.Col[i] 85 m = util.Min(bufs.RuneLen, c.Tag.Len()) 86 c.Tag.File.Read(0, r[:m]) 87 n = 0 88 for n < m && r[n] != '\n' { 89 n++ 90 } 91 fmt.Fprintf(b, "c%11d %s\n", i, string(r[:n])) 92 } 93 for i, c := range row.Col { 94 Windows: 95 for j, w := range c.W { 96 wind.Wincommit(w, &w.Tag) 97 t := &w.Body 98 // windows owned by others get special treatment 99 if w.External { 100 if w.Dumpstr == "" { 101 continue 102 } 103 } 104 // zeroxes of external windows are tossed 105 if len(t.File.Text) > 1 { 106 for n = 0; n < len(t.File.Text); n++ { 107 w1 := t.File.Text[n].W 108 if w == w1 { 109 continue 110 } 111 if w1.External { 112 continue Windows 113 } 114 } 115 } 116 fontname := "" 117 if t.Reffont.F != adraw.Font { 118 fontname = t.Reffont.F.Name 119 } 120 var a string 121 if len(t.File.Name()) != 0 { 122 a = string(t.File.Name()) 123 } 124 var dumped bool 125 if dumpid[t.File] != 0 { 126 dumped = false 127 fmt.Fprintf(b, "x%11d %11d %11d %11d %11.7f %s\n", i, dumpid[t.File], w.Body.Q0, w.Body.Q1, 100.0*float64(w.R.Min.Y-c.R.Min.Y)/float64(c.R.Dy()), fontname) 128 } else if w.Dumpstr != "" { 129 dumped = false 130 fmt.Fprintf(b, "e%11d %11d %11d %11d %11.7f %s\n", i, 0, 0, 0, 100.0*float64(w.R.Min.Y-c.R.Min.Y)/float64(c.R.Dy()), fontname) 131 } else if (!w.Dirty && exists(a)) || w.IsDir { 132 dumped = false 133 dumpid[t.File] = w.ID 134 fmt.Fprintf(b, "f%11d %11d %11d %11d %11.7f %s\n", i, w.ID, w.Body.Q0, w.Body.Q1, 100.0*float64(w.R.Min.Y-c.R.Min.Y)/float64(c.R.Dy()), fontname) 135 } else { 136 dumped = true 137 dumpid[t.File] = w.ID 138 fmt.Fprintf(b, "F%11d %11d %11d %11d %11.7f %11d %s\n", i, j, w.Body.Q0, w.Body.Q1, 100.0*float64(w.R.Min.Y-c.R.Min.Y)/float64(c.R.Dy()), w.Body.Len(), fontname) 139 } 140 b.WriteString(wind.Winctlprint(w, false)) 141 m = util.Min(bufs.RuneLen, w.Tag.Len()) 142 w.Tag.File.Read(0, r[:m]) 143 if !containsRune(r[:m], '|') { 144 alog.Printf("dump: window %d has no | in tag %q!", w.ID, string(r[:m])) 145 } 146 n = 0 147 for n < m { 148 start := n 149 for n < m && r[n] != '\n' { 150 n++ 151 } 152 fmt.Fprintf(b, "%s", string(r[start:n])) 153 if n < m { 154 b.WriteByte(0xff) // \n in tag becomes 0xff byte (invalid UTF) 155 n++ 156 } 157 } 158 fmt.Fprintf(b, "\n") 159 if dumped { 160 q0 := 0 161 q1 := t.Len() 162 for q0 < q1 { 163 n = q1 - q0 164 if n > bufs.Len/utf8.UTFMax { 165 n = bufs.Len / utf8.UTFMax 166 } 167 t.File.Read(q0, r[:n]) 168 fmt.Fprintf(b, "%s", string(r[:n])) 169 q0 += n 170 } 171 } 172 if w.Dumpstr != "" { 173 if w.Dumpdir != "" { 174 fmt.Fprintf(b, "%s\n%s\n", w.Dumpdir, w.Dumpstr) 175 } else { 176 fmt.Fprintf(b, "\n%s\n", w.Dumpstr) 177 } 178 } 179 } 180 } 181 b.Flush() // TODO(rsc): err check 182 f.Close() // TODO(rsc): err check 183 bufs.FreeRunes(r) 184 } 185 186 func containsRune(r []rune, c rune) bool { 187 for _, rc := range r { 188 if rc == c { 189 return true 190 } 191 } 192 return false 193 } 194 195 func exists(file string) bool { 196 _, err := os.Stat(file) 197 return err == nil 198 } 199 200 func rdline(b *bufio.Reader, linep *int) (string, error) { 201 l, err := b.ReadString('\n') 202 if err == nil { 203 (*linep)++ 204 } 205 return l, err 206 } 207 208 /* 209 * Get font names from load file so we don't load fonts we won't use 210 */ 211 func LoadFonts(file string) { 212 f, err := os.Open(file) 213 if err != nil { 214 return 215 } 216 defer f.Close() 217 b := bufio.NewReader(f) 218 // current directory 219 _, err = b.ReadString('\n') 220 if err != nil { 221 return 222 } 223 // global fonts 224 for i := 0; i < 2; i++ { 225 l, err := b.ReadString('\n') 226 if err != nil { 227 return 228 } 229 l = l[:len(l)-1] 230 if l != "" && l != adraw.FontNames[i] { 231 adraw.FontNames[i] = l 232 } 233 } 234 } 235 236 func Load(row *wind.Row, file *string, initing bool) bool { 237 if file == nil { 238 if Home == "" { 239 alog.Printf("can't find file for load: $home not defined\n") 240 return false 241 } 242 s := fmt.Sprintf("%s/acme.dump", Home) 243 file = &s 244 } 245 f, err := os.Open(*file) 246 if err != nil { 247 alog.Printf("can't open load file %s: %v\n", *file, err) 248 return false 249 } 250 defer f.Close() 251 b := bufio.NewReader(f) 252 253 // current directory 254 line := 0 255 bad := func() bool { 256 alog.Printf("bad load file %s:%d\n", *file, line) 257 return false 258 } 259 l, err := rdline(b, &line) 260 if err != nil { 261 return bad() 262 } 263 l = l[:len(l)-1] 264 if err := os.Chdir(l); err != nil { 265 alog.Printf("can't chdir %s\n", l) 266 return bad() 267 } 268 269 // global fonts 270 var i int 271 for i = 0; i < 2; i++ { 272 l, err := rdline(b, &line) 273 if err != nil { 274 return bad() 275 } 276 l = l[:len(l)-1] 277 if l != "" && l != adraw.FontNames[i] { 278 adraw.FindFont(i != 0, true, i == 0 && initing, l) 279 } 280 } 281 if initing && len(row.Col) == 0 { 282 wind.RowInit(row, adraw.Display.ScreenImage.Clipr) 283 } 284 l, err = rdline(b, &line) 285 if err != nil { 286 return bad() 287 } 288 j := len(l) / 12 289 if j <= 0 || j > 10 { 290 return bad() 291 } 292 var percent float64 293 for i = 0; i < j; i++ { 294 percent = atof(l[i*12 : (i+1)*12]) 295 if percent < 0 || percent >= 100 { 296 return bad() 297 } 298 x := row.R.Min.X + int(percent*float64(row.R.Dx())/100+0.5) 299 if i < len(row.Col) { 300 if i == 0 { 301 continue 302 } 303 c1 := row.Col[i-1] 304 c2 := row.Col[i] 305 r1 := c1.R 306 r2 := c2.R 307 if x < adraw.Border() { 308 x = adraw.Border() 309 } 310 r1.Max.X = x - adraw.Border() 311 r2.Min.X = x 312 if r1.Dx() < 50 || r2.Dx() < 50 { 313 continue 314 } 315 adraw.Display.ScreenImage.Draw(draw.Rpt(r1.Min, r2.Max), adraw.Display.White, nil, draw.ZP) 316 wind.Colresize(c1, r1) 317 wind.Colresize(c2, r2) 318 r2.Min.X = x - adraw.Border() 319 r2.Max.X = x 320 adraw.Display.ScreenImage.Draw(r2, adraw.Display.Black, nil, draw.ZP) 321 } 322 if i >= len(row.Col) { 323 wind.RowAdd(row, nil, x) 324 } 325 } 326 var n int 327 var ns int 328 var r []rune 329 hdrdone := false 330 byDumpID := make(map[int]*wind.Window) 331 for { 332 l, err = rdline(b, &line) 333 if err != nil { 334 break 335 } 336 if !hdrdone { 337 switch l[0] { 338 case 'c': 339 l = l[:len(l)-1] 340 i = atoi(l[1:12]) 341 r = []rune(l[1*12:]) 342 ns = -1 343 for n = 0; n < len(r); n++ { 344 if r[n] == '/' { 345 ns = n 346 } 347 if r[n] == ' ' { 348 break 349 } 350 } 351 wind.Textdelete(&row.Col[i].Tag, 0, row.Col[i].Tag.Len(), true) 352 wind.Textinsert(&row.Col[i].Tag, 0, r[n+1:], true) 353 continue 354 case 'w': 355 l = l[:len(l)-1] 356 r = []rune(l[2:]) 357 ns = -1 358 for n = 0; n < len(r); n++ { 359 if r[n] == '/' { 360 ns = n 361 } 362 if r[n] == ' ' { 363 break 364 } 365 } 366 wind.Textdelete(&row.Tag, 0, row.Tag.Len(), true) 367 wind.Textinsert(&row.Tag, 0, r, true) 368 continue 369 } 370 hdrdone = true 371 } 372 dumpid := 0 373 var fontname string 374 var ndumped int 375 switch l[0] { 376 case 'e': 377 if len(l) < 1+5*12+1 { 378 return bad() 379 } 380 l, err = rdline(b, &line) // ctl line; ignored 381 if err != nil { 382 return bad() 383 } 384 l, err = rdline(b, &line) // directory 385 if err != nil { 386 return bad() 387 } 388 l = l[:len(l)-1] 389 if len(l) == 0 { 390 if Home == "" { 391 r = []rune("./") 392 } else { 393 r = []rune(Home + "/") 394 } 395 } else { 396 r = []rune(l) 397 } 398 l, err = rdline(b, &line) // command 399 if err != nil { 400 return bad() 401 } 402 Run(l, r) 403 continue 404 case 'f': 405 if len(l) < 1+5*12+1 { 406 return bad() 407 } 408 l = l[:len(l)-1] 409 fontname = l[1+5*12:] 410 ndumped = -1 411 case 'F': 412 if len(l) < 1+6*12+1 { 413 return bad() 414 } 415 l = l[:len(l)-1] 416 fontname = l[1+6*12:] 417 ndumped = atoi(l[1+5*12+1:]) 418 case 'x': 419 if len(l) < 1+5*12+1 { 420 return bad() 421 } 422 l = l[:len(l)-1] 423 fontname = l[1+5*12:] 424 ndumped = -1 425 dumpid = atoi(l[1+1*12:]) 426 default: 427 return bad() 428 } 429 var fontr []rune 430 if fontname != "" { 431 fontr = []rune(fontname) 432 } 433 i = atoi(l[1+0*12:]) 434 j = atoi(l[1+1*12:]) 435 q0 := atoi(l[1+2*12:]) 436 q1 := atoi(l[1+3*12:]) 437 percent = atof(l[1+4*12:]) 438 if i < 0 || i > 10 { 439 return bad() 440 } 441 if i > len(row.Col) { 442 i = len(row.Col) 443 } 444 c := row.Col[i] 445 y := c.R.Min.Y + int((percent*float64(c.R.Dy()))/100+0.5) 446 if y < c.R.Min.Y || y >= c.R.Max.Y { 447 y = -1 448 } 449 var w *wind.Window 450 if dumpid == 0 { 451 w = wind.Coladd(c, nil, nil, y) 452 } else { 453 w = wind.Coladd(c, nil, byDumpID[dumpid], y) 454 } 455 if w == nil { 456 continue 457 } 458 byDumpID[j] = w 459 l, err = rdline(b, &line) 460 if err != nil { 461 return bad() 462 } 463 l = l[:len(l)-1] 464 // convert 0xff in multiline tag back to \n 465 lb := []byte(l) 466 for i = 0; i < len(lb); i++ { 467 if lb[i] == 0xff { 468 lb[i] = '\n' 469 } 470 } 471 l = string(lb) 472 r = []rune(l[5*12:]) 473 ns = -1 474 for n = 0; n < len(r); n++ { 475 if r[n] == '/' { 476 ns = n 477 } 478 if r[n] == ' ' { 479 break 480 } 481 } 482 if dumpid == 0 { 483 wind.Winsetname(w, r[:n]) 484 } 485 for ; n < len(r); n++ { 486 if r[n] == '|' { 487 break 488 } 489 } 490 wind.Wincleartatg(w) 491 if n < len(r) { 492 wind.Textinsert(&w.Tag, w.Tag.Len(), r[n+1:], true) 493 } else { 494 alog.Printf("load: found window tag with no | character (tag: %q)", string(r)) 495 } 496 if ndumped >= 0 { 497 // simplest thing is to put it in a file and load that 498 f, err := ioutil.TempFile("", fmt.Sprintf("acme.%d.*", os.Getpid())) 499 if err != nil { 500 alog.Printf("can't create temp file: %v\n", err) 501 return bad() 502 } 503 defer f.Close() 504 bout := bufio.NewWriter(f) 505 for n = 0; n < ndumped; n++ { 506 ch, _, err := b.ReadRune() 507 if err != nil { 508 return bad() 509 } 510 bout.WriteRune(ch) 511 } 512 if err := bout.Flush(); err != nil { 513 return bad() 514 } 515 tmp := f.Name() 516 if err := f.Close(); err != nil { 517 return bad() 518 } 519 fileload.Textload(&w.Body, 0, tmp, true) 520 os.Remove(tmp) 521 w.Body.File.SetMod(true) 522 for n = 0; n < len(w.Body.File.Text); n++ { 523 w.Body.File.Text[n].W.Dirty = true 524 } 525 wind.Winsettag(w) 526 } else if dumpid == 0 && r[ns+1] != '+' && r[ns+1] != '-' { 527 Get(&w.Body) 528 } 529 if fontr != nil { 530 fmt.Fprintf(os.Stderr, "FONTR %q\n", fontr) 531 ui.Fontx(&w.Body, nil, nil, false, false, fontr) 532 } 533 if q0 > w.Body.Len() || q1 > w.Body.Len() || q0 > q1 { 534 q1 = 0 535 q0 = q1 536 } 537 wind.Textshow(&w.Body, q0, q1, true) 538 w.Maxlines = util.Min(w.Body.Fr.NumLines, util.Max(w.Maxlines, w.Body.Fr.MaxLines)) 539 OnNewWindow(w) 540 } 541 return true 542 } 543 544 func atoi(s string) int { 545 for s != "" && s[0] == ' ' { 546 s = s[1:] 547 } 548 v := 0 549 for i := 0; i < len(s) && '0' <= s[i] && s[i] <= '9'; i++ { 550 v = v*10 + int(s[i]-'0') 551 } 552 return v 553 } 554 555 func atof(s string) float64 { 556 for s != "" && s[0] == ' ' { 557 s = s[1:] 558 } 559 i := 0 560 for i < len(s) && ('0' <= s[i] && s[i] <= '9' || s[i] == '.') { 561 i++ 562 } 563 f, err := strconv.ParseFloat(s[:i], 64) 564 if err != nil { 565 f = 0 566 } 567 return f 568 }