9fans.net/go@v0.0.7/cmd/acme/util.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 <plumb.h>
    11  // #include <libsec.h>
    12  // #include "dat.h"
    13  // #include "fns.h"
    14  
    15  package main
    16  
    17  import (
    18  	"fmt"
    19  
    20  	"9fans.net/go/cmd/acme/internal/bufs"
    21  	"9fans.net/go/cmd/acme/internal/disk"
    22  	"9fans.net/go/cmd/acme/internal/runes"
    23  	"9fans.net/go/cmd/acme/internal/ui"
    24  	"9fans.net/go/cmd/acme/internal/util"
    25  	"9fans.net/go/cmd/acme/internal/wind"
    26  	"9fans.net/go/cmd/internal/base"
    27  )
    28  
    29  func errorwin1(dir []rune, incl [][]rune) *wind.Window {
    30  	var r []rune
    31  	if len(dir) > 0 {
    32  		r = append(r, dir...)
    33  		r = append(r, '/')
    34  	}
    35  	r = append(r, []rune("+Errors")...)
    36  	w := ui.LookFile(r)
    37  	if w == nil {
    38  		if len(wind.TheRow.Col) == 0 {
    39  			if wind.RowAdd(&wind.TheRow, nil, -1) == nil {
    40  				util.Fatal("can't create column to make error window")
    41  			}
    42  		}
    43  		w = ui.ColaddAndMouse(wind.TheRow.Col[len(wind.TheRow.Col)-1], nil, nil, -1)
    44  		w.Filemenu = false
    45  		wind.Winsetname(w, r)
    46  		xfidlog(w, "new")
    47  	}
    48  	for i := len(incl) - 1; i >= 0; i-- {
    49  		wind.Winaddincl(w, runes.Clone(incl[i]))
    50  	}
    51  	w.Autoindent = wind.GlobalAutoindent
    52  	return w
    53  }
    54  
    55  // make new window, if necessary; return with it locked
    56  func errorwin(md *base.Mntdir, owner rune) *wind.Window {
    57  	var w *wind.Window
    58  	for {
    59  		if md == nil {
    60  			w = errorwin1(nil, nil)
    61  		} else {
    62  			w = errorwin1(md.Dir, md.Incl)
    63  		}
    64  		wind.Winlock(w, owner)
    65  		if w.Col != nil {
    66  			break
    67  		}
    68  		// window was deleted too fast
    69  		wind.Winunlock(w)
    70  	}
    71  	return w
    72  }
    73  
    74  /*
    75   * Incoming window should be locked.
    76   * It will be unlocked and returned window
    77   * will be locked in its place.
    78   */
    79  func errorwinforwin(w *wind.Window) *wind.Window {
    80  	t := &w.Body
    81  	dir := wind.Dirname(t, nil)
    82  	if len(dir) == 1 && dir[0] == '.' { // sigh
    83  		dir = nil
    84  	}
    85  	incl := make([][]rune, len(w.Incl))
    86  	for i := range w.Incl {
    87  		incl[i] = runes.Clone(w.Incl[i])
    88  	}
    89  	owner := w.Owner
    90  	wind.Winunlock(w)
    91  	for {
    92  		w = errorwin1(dir, incl)
    93  		wind.Winlock(w, owner)
    94  		if w.Col != nil {
    95  			break
    96  		}
    97  		// window deleted too fast
    98  		wind.Winunlock(w)
    99  	}
   100  	return w
   101  }
   102  
   103  type Warning struct {
   104  	md   *base.Mntdir
   105  	buf  disk.Buffer
   106  	next *Warning
   107  }
   108  
   109  var warnings *Warning
   110  
   111  func addwarningtext(md *base.Mntdir, r []rune) {
   112  	for warn := warnings; warn != nil; warn = warn.next {
   113  		if warn.md == md {
   114  			warn.buf.Insert(warn.buf.Len(), r)
   115  			return
   116  		}
   117  	}
   118  	warn := new(Warning)
   119  	warn.next = warnings
   120  	warn.md = md
   121  	if md != nil {
   122  		fsysincid(md)
   123  	}
   124  	warnings = warn
   125  	warn.buf.Insert(0, r)
   126  	select {
   127  	case cwarn <- 0:
   128  	default:
   129  	}
   130  }
   131  
   132  // called while row is locked
   133  func flushwarnings() {
   134  	var next *Warning
   135  	for warn := warnings; warn != nil; warn = next {
   136  		w := errorwin(warn.md, 'E')
   137  		t := &w.Body
   138  		owner := w.Owner
   139  		if owner == 0 {
   140  			w.Owner = 'E'
   141  		}
   142  		wind.Wincommit(w, t)
   143  		/*
   144  		 * Most commands don't generate much output. For instance,
   145  		 * Edit ,>cat goes through /dev/cons and is already in blocks
   146  		 * because of the i/o system, but a few can.  Edit ,p will
   147  		 * put the entire result into a single hunk.  So it's worth doing
   148  		 * this in blocks (and putting the text in a buffer in the first
   149  		 * place), to avoid a big memory footprint.
   150  		 */
   151  		r := bufs.AllocRunes()
   152  		q0 := t.Len()
   153  		var nr int
   154  		for n := 0; n < warn.buf.Len(); n += nr {
   155  			nr = warn.buf.Len() - n
   156  			if nr > bufs.RuneLen {
   157  				nr = bufs.RuneLen
   158  			}
   159  			warn.buf.Read(n, r[:nr])
   160  			wind.Textbsinsert(t, t.Len(), r[:nr], true, &nr)
   161  		}
   162  		wind.Textshow(t, q0, t.Len(), true)
   163  		wind.Winsettag(t.W)
   164  		wind.Textscrdraw(t)
   165  		w.Owner = owner
   166  		w.Dirty = false
   167  		wind.Winunlock(w)
   168  		warn.buf.Close()
   169  		next = warn.next
   170  		if warn.md != nil {
   171  			fsysdelid(warn.md)
   172  		}
   173  	}
   174  	warnings = nil
   175  }
   176  
   177  func warning(md *base.Mntdir, format string, args ...interface{}) {
   178  	addwarningtext(md, []rune(fmt.Sprintf(format, args...)))
   179  }
   180  
   181  func rgetc(v interface{}, n int) rune {
   182  	r := v.([]rune)
   183  	if n >= len(r) {
   184  		return 0
   185  	}
   186  	return r[n]
   187  }