diff --git a/README.md b/README.md index 0e0cd6f5..f63732f3 100644 --- a/README.md +++ b/README.md @@ -1208,6 +1208,14 @@ If you want to enable this option by default, set `QuitSmall` to `true` in the c QuitSmall: true ``` +With `--wrap=none`, `QuitSmall` only checks whether the content fits vertically. When the current screen is written on exit (`IsWriteOriginal: false`, the default), lines wider than the screen are truncated. If you want `ov` to stay open whenever no-wrap content extends beyond the screen width, set `QuitSmallNoTruncate` to `true`. + +```yaml +QuitSmallNoTruncate: true +``` + +`QuitSmallNoTruncate` has no effect when `IsWriteOriginal: true`, because the original lines are written in full regardless of the screen width. + ### 4.28. Suspend You can suspend ov with `Ctrl+z`(default key). diff --git a/ov-less.yaml b/ov-less.yaml index b6633783..2ef22817 100644 --- a/ov-less.yaml +++ b/ov-less.yaml @@ -2,6 +2,7 @@ # Copy it to `$XDG_CONFIG_HOME/ov/config.yaml` or start it with `ov --config ov.yaml`. # # QuitSmall: false # Quit if the file size is smaller than the terminal size. +# QuitSmallNoTruncate: false # Do not quit if no-wrap lines are wider than the screen. # IsWriteOriginal: false # Write the original content when exiting. # BeforeWriteOriginal: 0 # Extra lines above the current view to output on exit. # AfterWriteOriginal: 0 # Extra lines below the current view to output on exit. diff --git a/ov.yaml b/ov.yaml index b7953e1f..e9500178 100644 --- a/ov.yaml +++ b/ov.yaml @@ -2,6 +2,7 @@ # Copy it to `$XDG_CONFIG_HOME/ov/config.yaml` or start it with `ov --config ov.yaml`. # # QuitSmall: false # Quit if the file size is smaller than the terminal size. +# QuitSmallNoTruncate: false # Do not quit if no-wrap lines are wider than the screen. # IsWriteOriginal: false # Write the original content when exiting. # BeforeWriteOriginal: 0 # Extra lines above the current view to output on exit. # AfterWriteOriginal: 0 # Extra lines below the current view to output on exit. diff --git a/ov.yaml.template b/ov.yaml.template index 324449c4..5eed7b05 100644 --- a/ov.yaml.template +++ b/ov.yaml.template @@ -2,6 +2,7 @@ # Copy it to `$XDG_CONFIG_HOME/ov/config.yaml` or start it with `ov --config ov.yaml`. # # QuitSmall: false # Quit if the file size is smaller than the terminal size. +# QuitSmallNoTruncate: false # Do not quit if no-wrap lines are wider than the screen. # IsWriteOriginal: false # Write the original content when exiting. # BeforeWriteOriginal: 0 # Extra lines above the current view to output on exit. # AfterWriteOriginal: 0 # Extra lines below the current view to output on exit. diff --git a/oviewer/config.go b/oviewer/config.go index 8a83a751..651366c7 100644 --- a/oviewer/config.go +++ b/oviewer/config.go @@ -56,6 +56,9 @@ type Config struct { QuitSmall bool // QuitSmallFilter indicates whether to quit if the output fits on one screen and a filter is applied. QuitSmallFilter bool + // QuitSmallNoTruncate indicates whether to stay open when no-wrap lines are + // wider than the screen, instead of quitting with truncated output. + QuitSmallNoTruncate bool // CaseSensitive is case-sensitive if true. CaseSensitive bool // SmartCaseSensitive indicates whether lowercase search should ignore case. diff --git a/oviewer/oviewer.go b/oviewer/oviewer.go index 6bb649ad..ef3a1616 100644 --- a/oviewer/oviewer.go +++ b/oviewer/oviewer.go @@ -903,6 +903,9 @@ func (root *Root) docSmall() bool { if (end - start) >= bodyHeight { return false } + if root.Config.QuitSmallNoTruncate && !root.Config.IsWriteOriginal && root.hasTruncatedLine() { + return false + } strs := tcellansi.ScreenContentToStrings(root.Screen, 0, root.scr.vWidth, start, end) strs = tcellansi.TrimRightSpaces(strs) @@ -910,6 +913,19 @@ func (root *Root) docSmall() bool { return true } +// hasTruncatedLine reports whether no-wrap output exceeds the available line width. +func (root *Root) hasTruncatedLine() bool { + if root.Doc.WrapMode { + return false + } + for _, lineC := range root.scr.lines { + if lineC.valid && len(lineC.lc) > root.Doc.bodyWidth { + return true + } + } + return false +} + // OutputOnExit outputs to the terminal when exiting. func (root *Root) OutputOnExit() { output := os.Stdout diff --git a/oviewer/oviewer_test.go b/oviewer/oviewer_test.go index 3e932a10..5d7a6ab4 100644 --- a/oviewer/oviewer_test.go +++ b/oviewer/oviewer_test.go @@ -4,6 +4,7 @@ import ( "bytes" "context" "io" + "os" "path/filepath" "reflect" "testing" @@ -536,6 +537,54 @@ func TestRoot_docSmall(t *testing.T) { } } +func TestRoot_docSmallNoTruncate(t *testing.T) { + tcellNewScreen = fakeScreen + defer func() { + tcellNewScreen = tcell.NewScreen + }() + + fileName := filepath.Join(t.TempDir(), "long-line.txt") + if err := os.WriteFile(fileName, bytes.Repeat([]byte("x"), 81), 0o600); err != nil { + t.Fatal(err) + } + + tests := []struct { + name string + noTruncate bool + isWriteOriginal bool + want bool + }{ + { + name: "allow truncation", + noTruncate: false, + want: true, + }, + { + name: "prevent truncation", + noTruncate: true, + want: false, + }, + { + name: "original output is never truncated", + noTruncate: true, + isWriteOriginal: true, + want: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + root := rootFileReadHelper(t, fileName) + root.Doc.WrapMode = false + root.Config.QuitSmallNoTruncate = tt.noTruncate + root.Config.IsWriteOriginal = tt.isWriteOriginal + + if got := root.docSmall(); got != tt.want { + t.Errorf("Root.docSmall() = %v, want %v", got, tt.want) + } + }) + } +} + func TestRoot_setCaption(t *testing.T) { type fields struct { caption string