コード例 #1
0
ファイル: async_reader.go プロジェクト: rathinaganesh/elvish
func (ar *AsyncReader) Run() {
	fd := int(ar.rd.Fd())
	cfd := int(ar.rCtrl.Fd())
	maxfd := max(fd, cfd)
	fs := sys.NewFdSet()
	var cBuf [1]byte

	if nonblock, _ := sys.GetNonblock(fd); !nonblock {
		sys.SetNonblock(fd, true)
		defer sys.SetNonblock(fd, false)
	}

	for {
		fs.Set(fd, cfd)
		err := sys.Select(maxfd+1, fs, nil, nil, nil)
		if err != nil {
			switch err {
			case syscall.EINTR:
				continue
			default:
				panic(err)
			}
		}
		if fs.IsSet(cfd) {
			// Consume the written byte
			ar.rCtrl.Read(cBuf[:])
			ar.ackCtrl <- true
			return
		} else {
			r, _, err := ar.bufrd.ReadRune()
			switch err {
			case nil:
				ar.ch <- r
			case io.EOF:
				return
			default:
				// BUG(xiaq): AsyncReader relies on the undocumented fact
				// that (*os.File).Read returns an *os.File.PathError
				e := err.(*os.PathError).Err
				if e != syscall.EWOULDBLOCK && e != syscall.EAGAIN {
					panic(err)
				}
			}
		}
	}
}
コード例 #2
0
ファイル: async_reader.go プロジェクト: firebitsbr/elvish
// Run runs the AsyncReader. It blocks until Quit is called and should be
// called in a separate goroutine.
func (ar *AsyncReader) Run() {
	fd := int(ar.rd.Fd())
	cfd := int(ar.rCtrl.Fd())
	maxfd := max(fd, cfd)
	fs := sys.NewFdSet()
	var cBuf [1]byte

	if nonblock, _ := sys.GetNonblock(fd); !nonblock {
		sys.SetNonblock(fd, true)
		defer sys.SetNonblock(fd, false)
	}

	for {
		fs.Set(fd, cfd)
		err := sys.Select(maxfd+1, fs, nil, nil, nil)
		if err != nil {
			switch err {
			case syscall.EINTR:
				continue
			default:
				ar.errCh <- err
				return
			}
		}
		if fs.IsSet(cfd) {
			// Consume the written byte
			ar.rCtrl.Read(cBuf[:])
			<-ar.ctrlCh
			return
		}
	ReadRune:
		for {
			r, _, err := ar.bufrd.ReadRune()
			switch err {
			case nil:
				// Logger.Printf("read rune: %q", r)
				select {
				case ar.ch <- r:
				case <-ar.ctrlCh:
					ar.rCtrl.Read(cBuf[:])
					return
				}
			case io.EOF:
				return
			default:
				// BUG(xiaq): AsyncReader relies on the undocumented fact
				// that (*os.File).Read returns an *os.File.PathError
				patherr, ok := err.(*os.PathError) //.Err
				if !ok {
					ar.errCh <- err
					return
				}
				e := patherr.Err
				if e == syscall.EWOULDBLOCK || e == syscall.EAGAIN {
					break ReadRune
				} else {
					ar.errCh <- err
					return
				}
			}
		}
	}
}
コード例 #3
0
ファイル: writer.go プロジェクト: zhsj/elvish
// commitBuffer updates the terminal display to reflect current buffer.
// TODO Instead of erasing w.oldBuf entirely and then draw buf, compute a
// delta between w.oldBuf and buf
func (w *writer) commitBuffer(bufNoti, buf *buffer, fullRefresh bool) error {
	if buf.width != w.oldBuf.width && w.oldBuf.cells != nil {
		// Width change, force full refresh
		w.oldBuf.cells = nil
		fullRefresh = true
	}

	bytesBuf := new(bytes.Buffer)

	// Hide cursor.
	bytesBuf.WriteString("\033[?25l")

	// Rewind cursor
	if pLine := w.oldBuf.dot.line; pLine > 0 {
		fmt.Fprintf(bytesBuf, "\033[%dA", pLine)
	}
	bytesBuf.WriteString("\r")

	if fullRefresh {
		// Do an erase.
		bytesBuf.WriteString("\033[J")
	}

	// style of last written cell.
	style := ""

	switchStyle := func(newstyle string) {
		if newstyle != style {
			fmt.Fprintf(bytesBuf, "\033[0;%sm", newstyle)
			style = newstyle
		}
	}

	writeCells := func(cs []cell) {
		for _, c := range cs {
			if c.width > 0 {
				switchStyle(c.style)
			}
			bytesBuf.WriteString(string(c.rune))
		}
	}

	if bufNoti != nil {
		if logWriterDetail {
			Logger.Printf("going to write %d lines of notifications", len(bufNoti.cells))
		}

		// Write notifications
		for _, line := range bufNoti.cells {
			writeCells(line)
			switchStyle("")
			bytesBuf.WriteString("\033[K\n")
		}
		// XXX Hacky.
		if len(w.oldBuf.cells) > 0 {
			w.oldBuf.cells = w.oldBuf.cells[1:]
		}
	}

	if logWriterDetail {
		Logger.Printf("going to write %d lines, oldBuf had %d", len(buf.cells), len(w.oldBuf.cells))
	}

	for i, line := range buf.cells {
		if i > 0 {
			bytesBuf.WriteString("\n")
		}
		var j int // First column where buf and oldBuf differ
		// No need to update current line
		if !fullRefresh && i < len(w.oldBuf.cells) {
			var eq bool
			if eq, j = compareRows(line, w.oldBuf.cells[i]); eq {
				continue
			}
		}
		// Move to the first differing column if necessary.
		firstCol := widthOfCells(line[:j])
		if firstCol != 0 {
			fmt.Fprintf(bytesBuf, "\033[%dG", firstCol+1)
		}
		// Erase the rest of the line if necessary.
		if !fullRefresh && i < len(w.oldBuf.cells) && j < len(w.oldBuf.cells[i]) {
			switchStyle("")
			bytesBuf.WriteString("\033[K")
		}
		writeCells(line[j:])
	}
	if len(w.oldBuf.cells) > len(buf.cells) && !fullRefresh {
		// If the old buffer is higher, erase old content.
		// Note that we cannot simply write \033[J, because if the cursor is
		// just over the last column -- which is precisely the case if we have a
		// rprompt, \033[J will also erase the last column.
		switchStyle("")
		bytesBuf.WriteString("\n\033[J\033[A")
	}
	switchStyle("")
	cursor := buf.cursor()
	bytesBuf.Write(deltaPos(cursor, buf.dot))

	// Show cursor.
	bytesBuf.WriteString("\033[?25h")

	if logWriterDetail {
		Logger.Printf("going to write %q", bytesBuf.String())
	}

	fd := int(w.file.Fd())
	if nonblock, _ := sys.GetNonblock(fd); nonblock {
		sys.SetNonblock(fd, false)
		defer sys.SetNonblock(fd, true)
	}

	_, err := w.file.Write(bytesBuf.Bytes())
	if err != nil {
		return err
	}

	w.oldBuf = buf
	return nil
}
コード例 #4
0
ファイル: async_reader.go プロジェクト: wlihome/elvish
func (ar *AsyncReader) run() {
	fd := int(ar.rd.Fd())
	cfd := int(ar.rCtrl.Fd())
	maxfd := max(fd, cfd)
	fs := sys.NewFdSet()
	var cBuf [1]byte

	defer close(ar.ch)

	sys.SetNonblock(fd, true)

	for {
		fs.Set(fd, cfd)
		err := sys.Select(maxfd+1, fs, nil, nil, nil)
		if err != nil {
			switch err {
			case syscall.EINTR:
				continue
			default:
				panic(err)
			}
		}
		if fs.IsSet(cfd) {
			// Consume the written byte
			ar.rCtrl.Read(cBuf[:])
			switch cBuf[0] {
			case asyncReaderQuit:
				sys.SetNonblock(fd, false)
				ar.ackCtrl <- true
				return
			case asyncReaderContinue:
				ar.ackCtrl <- true
			case asyncReaderStop:
				sys.SetNonblock(fd, false)
				ar.ackCtrl <- true
			Stop:
				for {
					ar.rCtrl.Read(cBuf[:])
					switch cBuf[0] {
					case asyncReaderQuit:
						ar.ackCtrl <- true
						return
					case asyncReaderContinue:
						sys.SetNonblock(fd, true)
						ar.ackCtrl <- true
						break Stop
					case asyncReaderStop:
						ar.ackCtrl <- true
					}
				}
			}
		} else {
		ReadRune:
			for {
				r, _, err := ar.bufrd.ReadRune()
				switch err {
				case nil:
					ar.ch <- r
				case io.EOF:
					return
				default:
					// BUG(xiaq): AsyncReader relies on the undocumented fact
					// that (*os.File).Read returns an *os.File.PathError
					e := err.(*os.PathError).Err
					if e == syscall.EWOULDBLOCK || e == syscall.EAGAIN {
						break ReadRune
					} else {
						panic(err)
					}
				}
			}
		}
	}
}