github.com/oweisse/u-root@v0.0.0-20181109060735-d005ad25fef1/cmds/elvish/edit/navigation_preview.go (about)

     1  package edit
     2  
     3  import (
     4  	"errors"
     5  	"io"
     6  	"os"
     7  	"strings"
     8  	"unicode/utf8"
     9  
    10  	"github.com/u-root/u-root/cmds/elvish/edit/ui"
    11  	"github.com/u-root/u-root/cmds/elvish/util"
    12  )
    13  
    14  // previewBytes is the maximum number of bytes to preview a file.
    15  const previewBytes = 64 * 1024
    16  
    17  // Errors displayed in the preview area of navigation mode.
    18  var (
    19  	errNotRegular   = errors.New("no preview for non-regular file")
    20  	errNotValidUTF8 = errors.New("no preview for non-utf8 file")
    21  )
    22  
    23  type navFilePreview struct {
    24  	lines     []ui.Styled
    25  	fullWidth int
    26  	beginLine int
    27  }
    28  
    29  func newNavFilePreview(lines []string) *navFilePreview {
    30  	width := 0
    31  	convertedLines := make([]ui.Styled, len(lines))
    32  	for i, line := range lines {
    33  		// BUG: Handle tabstops correctly
    34  		convertedLine := strings.Replace(line, "\t", "    ", -1)
    35  		convertedLines[i] = ui.Unstyled(convertedLine)
    36  		width = max(width, util.Wcswidth(convertedLine))
    37  	}
    38  	return &navFilePreview{convertedLines, width, 0}
    39  }
    40  
    41  func (fp *navFilePreview) FullWidth(h int) int {
    42  	width := fp.fullWidth
    43  	if h < len(fp.lines) {
    44  		return width + 1
    45  	}
    46  	return width
    47  }
    48  
    49  func (fp *navFilePreview) List(h int) ui.Renderer {
    50  	if len(fp.lines) <= h {
    51  		logger.Printf("Height %d fit all lines", h)
    52  		return listingRenderer{fp.lines}
    53  	}
    54  	shown := fp.lines[fp.beginLine:]
    55  	if len(shown) > h {
    56  		shown = shown[:h]
    57  	}
    58  	logger.Printf("Showing lines %d to %d", fp.beginLine, fp.beginLine+len(shown))
    59  	return listingWithScrollBarRenderer{
    60  		listingRenderer{shown}, len(fp.lines),
    61  		fp.beginLine, fp.beginLine + len(shown), h}
    62  }
    63  
    64  func makeNavFilePreview(fname string) navPreview {
    65  	file, err := os.Open(fname)
    66  	if err != nil {
    67  		return newErrNavColumn(err)
    68  	}
    69  
    70  	info, err := file.Stat()
    71  	if err != nil {
    72  		return newErrNavColumn(err)
    73  	}
    74  	if (info.Mode() & (os.ModeDevice | os.ModeNamedPipe | os.ModeSocket | os.ModeCharDevice)) != 0 {
    75  		return newErrNavColumn(errNotRegular)
    76  	}
    77  
    78  	// BUG: when the file is bigger than the buffer, the scrollbar is wrong.
    79  	var buf [previewBytes]byte
    80  	nr, err := file.Read(buf[:])
    81  	if err != nil && err != io.EOF {
    82  		return newErrNavColumn(err)
    83  	}
    84  
    85  	content := buf[:nr]
    86  	if !utf8.Valid(content) {
    87  		return newErrNavColumn(errNotValidUTF8)
    88  	}
    89  
    90  	return newNavFilePreview(strings.Split(string(content), "\n"))
    91  }