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 }