@@ -10,6 +10,7 @@ import (
1010 "os"
1111 "os/exec"
1212 "path/filepath"
13+ "slices"
1314 "sort"
1415 "strconv"
1516 "strings"
@@ -22,6 +23,7 @@ import (
2223
2324 "github.com/alecthomas/chroma/v2/lexers"
2425 "github.com/charmbracelet/lipgloss"
26+ "github.com/charmbracelet/x/exp/term/ansi"
2527 "github.com/yorukot/ansichroma"
2628 "github.com/yorukot/superfile/src/config/icon"
2729 filepreview "github.com/yorukot/superfile/src/pkg/file_preview"
@@ -537,8 +539,6 @@ func (m *model) sortOptionsRender() string {
537539}
538540
539541func readFileContent (filepath string , maxLineLength int , previewLine int ) (string , error ) {
540- // String builder is much better for efficiency
541- // See - https://stackoverflow.com/questions/1760757/how-to-efficiently-concatenate-strings-in-go/47798475#47798475
542542 var resultBuilder strings.Builder
543543 file , err := os .Open (filepath )
544544 if err != nil {
@@ -550,12 +550,9 @@ func readFileContent(filepath string, maxLineLength int, previewLine int) (strin
550550 lineCount := 0
551551 for scanner .Scan () {
552552 line := scanner .Text ()
553- if len (line ) > maxLineLength {
554- line = line [:maxLineLength ]
555- }
556- // This is critical to avoid layout break, removes non Printable ASCII control characters.
557- line = common .MakePrintable (line )
558- resultBuilder .WriteString (line + "\n " )
553+ line = ansi .Truncate (line , maxLineLength , "" )
554+ resultBuilder .WriteString (line )
555+ resultBuilder .WriteRune ('\n' )
559556 lineCount ++
560557 if previewLine > 0 && lineCount >= previewLine {
561558 break
@@ -566,14 +563,21 @@ func readFileContent(filepath string, maxLineLength int, previewLine int) (strin
566563}
567564
568565func (m * model ) filePreviewPanelRender () string {
569- previewLine := m .mainPanelHeight + 2
566+ // Todo : This width adjustment must not be done inside render function. It should
567+ // only be triggered via Update()
570568 m .fileModel .filePreview .width += m .fullWidth - common .Config .SidebarWidth - m .fileModel .filePreview .width - ((m .fileModel .width + 2 ) * len (m .fileModel .filePanels )) - 2
571569
570+ return m .filePreviewPanelRenderWithDimensions (m .mainPanelHeight + 2 , m .fileModel .filePreview .width )
571+ }
572+
573+ func (m * model ) filePreviewPanelRenderWithDimensions (previewHeight int , previewWidth int ) string {
572574 panel := m .fileModel .filePanels [m .filePanelFocusIndex ]
573- box := common .FilePreviewBox (previewLine , m .fileModel .filePreview .width )
575+ box := common .FilePreviewBox (previewHeight , previewWidth )
576+ r := ui .FilePreviewPanelRenderer (previewHeight , previewWidth )
574577
575578 if len (panel .element ) == 0 {
576- return box .Render ("\n --- " + icon .Error + " No content to preview ---" )
579+ r .AddLines (common .FilePreviewNoContentText )
580+ return r .Render ()
577581 }
578582 // This could create errors if panel.cursor ever becomes negative, or goes out of bounds
579583 // We should have a panel validation function in our View() function
@@ -591,27 +595,30 @@ func (m *model) filePreviewPanelRender() string {
591595
592596 if infoErr != nil {
593597 slog .Error ("Error get file info" , "error" , infoErr )
594- return box .Render ("\n --- " + icon .Error + " Error get file info ---" )
598+ r .AddLines (common .FilePreviewNoFileInfoText )
599+ return r .Render ()
595600 }
596601
597602 ext := filepath .Ext (itemPath )
598603 // check if the file is unsupported file, cuz pdf will cause error
599- if ext == ".pdf" || ext == ".torrent" {
600- return box .Render ("\n --- " + icon .Error + " Unsupported formats ---" )
604+ if slices .Contains (common .UnsupportedPreviewFormats , ext ) {
605+ r .AddLines (common .FilePreviewUnsupportedFormatText )
606+ return r .Render ()
601607 }
602608
603609 if fileInfo .IsDir () {
604- directoryContent := ""
605610 dirPath := itemPath
606611
607612 files , err := os .ReadDir (dirPath )
608613 if err != nil {
609614 slog .Error ("Error render directory preview" , "error" , err )
610- return box .Render ("\n --- " + icon .Error + " Error render directory preview ---" )
615+ r .AddLines (common .FilePreviewDirectoryUnreadableText )
616+ return r .Render ()
611617 }
612618
613619 if len (files ) == 0 {
614- return box .Render ("\n --- empty ---" )
620+ r .AddLines (common .FilePreviewEmptyText )
621+ return r .Render ()
615622 }
616623
617624 sort .Slice (files , func (i , j int ) bool {
@@ -624,15 +631,17 @@ func (m *model) filePreviewPanelRender() string {
624631 return files [i ].Name () < files [j ].Name ()
625632 })
626633
627- for i := 0 ; i < previewLine && i < len (files ); i ++ {
634+ for i := 0 ; i < previewHeight && i < len (files ); i ++ {
628635 file := files [i ]
629- directoryContent += common .PrettierDirectoryPreviewName (file .Name (), file .IsDir (), common .FilePanelBGColor )
630- if i != previewLine - 1 && i != len (files )- 1 {
631- directoryContent += "\n "
632- }
636+
637+ style := common .GetElementIcon (file .Name (), file .IsDir (), common .Config .Nerdfont )
638+
639+ res := lipgloss .NewStyle ().Foreground (lipgloss .Color (style .Color )).Background (common .FilePanelBGColor ).
640+ Render (style .Icon + " " ) + common .FilePanelStyle .Render (file .Name ())
641+
642+ r .AddLines (res )
633643 }
634- directoryContent = common .CheckAndTruncateLineLengths (directoryContent , m .fileModel .filePreview .width )
635- return box .Render (directoryContent )
644+ return r .Render ()
636645 }
637646
638647 if isImageFile (itemPath ) {
@@ -645,7 +654,7 @@ func (m *model) filePreviewPanelRender() string {
645654 return box .Render ("\n --- Image preview is disabled ---" )
646655 }
647656
648- ansiRender , err := filepreview .ImagePreview (itemPath , m . fileModel . filePreview . width , previewLine , common .Theme .FilePanelBG )
657+ ansiRender , err := filepreview .ImagePreview (itemPath , previewWidth , previewHeight , common .Theme .FilePanelBG )
649658 if errors .Is (err , image .ErrFormat ) {
650659 return box .Render ("\n --- " + icon .Error + " Unsupported image formats ---" )
651660 }
@@ -671,7 +680,7 @@ func (m *model) filePreviewPanelRender() string {
671680 }
672681
673682 // At this point either format is not nil, or we can read the file
674- fileContent , err := readFileContent (itemPath , m . fileModel . width + 20 , previewLine )
683+ fileContent , err := readFileContent (itemPath , previewWidth , previewHeight )
675684 if err != nil {
676685 slog .Error ("Error open file" , "error" , err )
677686 return box .Render ("\n --- " + icon .Error + " Error open file ---" )
@@ -691,7 +700,7 @@ func (m *model) filePreviewPanelRender() string {
691700 if batCmd == "" {
692701 return box .Render ("\n --- " + icon .Error + " 'bat' is not installed or not found. ---\n --- Cannot render file preview. ---" )
693702 }
694- fileContent , err = getBatSyntaxHighlightedContent (itemPath , previewLine , background )
703+ fileContent , err = getBatSyntaxHighlightedContent (itemPath , previewHeight , background )
695704 } else {
696705 fileContent , err = ansichroma .HightlightString (fileContent , format .Config ().Name , common .Theme .CodeSyntaxHighlightTheme , background )
697706 }
@@ -700,9 +709,8 @@ func (m *model) filePreviewPanelRender() string {
700709 return box .Render ("\n --- " + icon .Error + " Error render code highlight ---" )
701710 }
702711 }
703-
704- fileContent = common .CheckAndTruncateLineLengths (fileContent , m .fileModel .filePreview .width )
705- return box .Render (fileContent )
712+ r .AddLines (fileContent )
713+ return r .Render ()
706714}
707715
708716func getBatSyntaxHighlightedContent (itemPath string , previewLine int , background string ) (string , error ) {
0 commit comments