mirror of
https://github.com/junegunn/fzf.git
synced 2026-02-20 08:38:37 +08:00
Implement word wrapping in the list section
This commit is contained in:
@@ -3,6 +3,14 @@ CHANGELOG
|
||||
|
||||
0.68.0
|
||||
------
|
||||
- Implemented word wrapping in the list section
|
||||
- Added `--wrap=word` (or `--wrap-word`) option and `toggle-wrap-word` action
|
||||
for word-level line wrapping in the list section
|
||||
- Changed default binding of `ctrl-/` and `alt-/` from `toggle-wrap` to
|
||||
`toggle-wrap-word`
|
||||
```sh
|
||||
fzf --wrap=word
|
||||
```
|
||||
- Implemented word wrapping in the preview window
|
||||
- Added `wrap-word` flag for `--preview-window` to enable word-level wrapping
|
||||
- Added `toggle-preview-wrap-word` action
|
||||
|
||||
@@ -593,8 +593,11 @@ Highlight the whole current line
|
||||
.B "\-\-cycle"
|
||||
Enable cyclic scroll
|
||||
.TP
|
||||
.B "\-\-wrap"
|
||||
Enable line wrap
|
||||
.BI "\-\-wrap" "[=MODE]"
|
||||
Enable line wrap. \fIMODE\fR can be \fBchar\fR (default) or \fBword\fR.
|
||||
\fBword\fR mode wraps lines at word boundaries (spaces and tabs) instead of
|
||||
at arbitrary character positions. \fB\-\-wrap\-word\fR is a synonym for
|
||||
\fB\-\-wrap=word\fR.
|
||||
.TP
|
||||
.BI "\-\-wrap\-sign" "=INDICATOR"
|
||||
Indicator for wrapped lines. The default is '↳ ' or '> ' depending on
|
||||
@@ -1968,7 +1971,8 @@ A key or an event can be bound to one or more of the following actions.
|
||||
\fBtoggle\-sort\fR
|
||||
\fBtoggle\-track\fR (toggle global tracking option (\fB\-\-track\fR))
|
||||
\fBtoggle\-track\-current\fR (toggle tracking of the current item)
|
||||
\fBtoggle\-wrap\fR \fIctrl\-/\fR \fIalt\-/\fR
|
||||
\fBtoggle\-wrap\fR
|
||||
\fBtoggle\-wrap\-word\fR \fIctrl\-/\fR \fIalt\-/\fR
|
||||
\fBtoggle+down\fR \fIctrl\-i (tab)\fR
|
||||
\fBtoggle+up\fR \fIbtab (shift\-tab)\fR
|
||||
\fBtrack\-current\fR (track the current item; automatically disabled if focus changes)
|
||||
|
||||
@@ -75,115 +75,116 @@ func _() {
|
||||
_ = x[actToggleTrackCurrent-64]
|
||||
_ = x[actToggleHeader-65]
|
||||
_ = x[actToggleWrap-66]
|
||||
_ = x[actToggleMultiLine-67]
|
||||
_ = x[actToggleHscroll-68]
|
||||
_ = x[actToggleRaw-69]
|
||||
_ = x[actEnableRaw-70]
|
||||
_ = x[actDisableRaw-71]
|
||||
_ = x[actTrackCurrent-72]
|
||||
_ = x[actToggleInput-73]
|
||||
_ = x[actHideInput-74]
|
||||
_ = x[actShowInput-75]
|
||||
_ = x[actUntrackCurrent-76]
|
||||
_ = x[actDown-77]
|
||||
_ = x[actDownMatch-78]
|
||||
_ = x[actUp-79]
|
||||
_ = x[actUpMatch-80]
|
||||
_ = x[actPageUp-81]
|
||||
_ = x[actPageDown-82]
|
||||
_ = x[actPosition-83]
|
||||
_ = x[actHalfPageUp-84]
|
||||
_ = x[actHalfPageDown-85]
|
||||
_ = x[actOffsetUp-86]
|
||||
_ = x[actOffsetDown-87]
|
||||
_ = x[actOffsetMiddle-88]
|
||||
_ = x[actJump-89]
|
||||
_ = x[actJumpAccept-90]
|
||||
_ = x[actPrintQuery-91]
|
||||
_ = x[actRefreshPreview-92]
|
||||
_ = x[actReplaceQuery-93]
|
||||
_ = x[actToggleSort-94]
|
||||
_ = x[actShowPreview-95]
|
||||
_ = x[actHidePreview-96]
|
||||
_ = x[actTogglePreview-97]
|
||||
_ = x[actTogglePreviewWrap-98]
|
||||
_ = x[actTogglePreviewWrapWord-99]
|
||||
_ = x[actTransform-100]
|
||||
_ = x[actTransformBorderLabel-101]
|
||||
_ = x[actTransformGhost-102]
|
||||
_ = x[actTransformHeader-103]
|
||||
_ = x[actTransformFooter-104]
|
||||
_ = x[actTransformHeaderLabel-105]
|
||||
_ = x[actTransformFooterLabel-106]
|
||||
_ = x[actTransformInputLabel-107]
|
||||
_ = x[actTransformListLabel-108]
|
||||
_ = x[actTransformNth-109]
|
||||
_ = x[actTransformPointer-110]
|
||||
_ = x[actTransformPreviewLabel-111]
|
||||
_ = x[actTransformPrompt-112]
|
||||
_ = x[actTransformQuery-113]
|
||||
_ = x[actTransformSearch-114]
|
||||
_ = x[actTrigger-115]
|
||||
_ = x[actBgTransform-116]
|
||||
_ = x[actBgTransformBorderLabel-117]
|
||||
_ = x[actBgTransformGhost-118]
|
||||
_ = x[actBgTransformHeader-119]
|
||||
_ = x[actBgTransformFooter-120]
|
||||
_ = x[actBgTransformHeaderLabel-121]
|
||||
_ = x[actBgTransformFooterLabel-122]
|
||||
_ = x[actBgTransformInputLabel-123]
|
||||
_ = x[actBgTransformListLabel-124]
|
||||
_ = x[actBgTransformNth-125]
|
||||
_ = x[actBgTransformPointer-126]
|
||||
_ = x[actBgTransformPreviewLabel-127]
|
||||
_ = x[actBgTransformPrompt-128]
|
||||
_ = x[actBgTransformQuery-129]
|
||||
_ = x[actBgTransformSearch-130]
|
||||
_ = x[actBgCancel-131]
|
||||
_ = x[actSearch-132]
|
||||
_ = x[actPreview-133]
|
||||
_ = x[actPreviewTop-134]
|
||||
_ = x[actPreviewBottom-135]
|
||||
_ = x[actPreviewUp-136]
|
||||
_ = x[actPreviewDown-137]
|
||||
_ = x[actPreviewPageUp-138]
|
||||
_ = x[actPreviewPageDown-139]
|
||||
_ = x[actPreviewHalfPageUp-140]
|
||||
_ = x[actPreviewHalfPageDown-141]
|
||||
_ = x[actPrevHistory-142]
|
||||
_ = x[actPrevSelected-143]
|
||||
_ = x[actPrint-144]
|
||||
_ = x[actPut-145]
|
||||
_ = x[actNextHistory-146]
|
||||
_ = x[actNextSelected-147]
|
||||
_ = x[actExecute-148]
|
||||
_ = x[actExecuteSilent-149]
|
||||
_ = x[actExecuteMulti-150]
|
||||
_ = x[actSigStop-151]
|
||||
_ = x[actBest-152]
|
||||
_ = x[actFirst-153]
|
||||
_ = x[actLast-154]
|
||||
_ = x[actReload-155]
|
||||
_ = x[actReloadSync-156]
|
||||
_ = x[actDisableSearch-157]
|
||||
_ = x[actEnableSearch-158]
|
||||
_ = x[actSelect-159]
|
||||
_ = x[actDeselect-160]
|
||||
_ = x[actUnbind-161]
|
||||
_ = x[actRebind-162]
|
||||
_ = x[actToggleBind-163]
|
||||
_ = x[actBecome-164]
|
||||
_ = x[actShowHeader-165]
|
||||
_ = x[actHideHeader-166]
|
||||
_ = x[actBell-167]
|
||||
_ = x[actExclude-168]
|
||||
_ = x[actExcludeMulti-169]
|
||||
_ = x[actAsync-170]
|
||||
_ = x[actToggleWrapWord-67]
|
||||
_ = x[actToggleMultiLine-68]
|
||||
_ = x[actToggleHscroll-69]
|
||||
_ = x[actToggleRaw-70]
|
||||
_ = x[actEnableRaw-71]
|
||||
_ = x[actDisableRaw-72]
|
||||
_ = x[actTrackCurrent-73]
|
||||
_ = x[actToggleInput-74]
|
||||
_ = x[actHideInput-75]
|
||||
_ = x[actShowInput-76]
|
||||
_ = x[actUntrackCurrent-77]
|
||||
_ = x[actDown-78]
|
||||
_ = x[actDownMatch-79]
|
||||
_ = x[actUp-80]
|
||||
_ = x[actUpMatch-81]
|
||||
_ = x[actPageUp-82]
|
||||
_ = x[actPageDown-83]
|
||||
_ = x[actPosition-84]
|
||||
_ = x[actHalfPageUp-85]
|
||||
_ = x[actHalfPageDown-86]
|
||||
_ = x[actOffsetUp-87]
|
||||
_ = x[actOffsetDown-88]
|
||||
_ = x[actOffsetMiddle-89]
|
||||
_ = x[actJump-90]
|
||||
_ = x[actJumpAccept-91]
|
||||
_ = x[actPrintQuery-92]
|
||||
_ = x[actRefreshPreview-93]
|
||||
_ = x[actReplaceQuery-94]
|
||||
_ = x[actToggleSort-95]
|
||||
_ = x[actShowPreview-96]
|
||||
_ = x[actHidePreview-97]
|
||||
_ = x[actTogglePreview-98]
|
||||
_ = x[actTogglePreviewWrap-99]
|
||||
_ = x[actTogglePreviewWrapWord-100]
|
||||
_ = x[actTransform-101]
|
||||
_ = x[actTransformBorderLabel-102]
|
||||
_ = x[actTransformGhost-103]
|
||||
_ = x[actTransformHeader-104]
|
||||
_ = x[actTransformFooter-105]
|
||||
_ = x[actTransformHeaderLabel-106]
|
||||
_ = x[actTransformFooterLabel-107]
|
||||
_ = x[actTransformInputLabel-108]
|
||||
_ = x[actTransformListLabel-109]
|
||||
_ = x[actTransformNth-110]
|
||||
_ = x[actTransformPointer-111]
|
||||
_ = x[actTransformPreviewLabel-112]
|
||||
_ = x[actTransformPrompt-113]
|
||||
_ = x[actTransformQuery-114]
|
||||
_ = x[actTransformSearch-115]
|
||||
_ = x[actTrigger-116]
|
||||
_ = x[actBgTransform-117]
|
||||
_ = x[actBgTransformBorderLabel-118]
|
||||
_ = x[actBgTransformGhost-119]
|
||||
_ = x[actBgTransformHeader-120]
|
||||
_ = x[actBgTransformFooter-121]
|
||||
_ = x[actBgTransformHeaderLabel-122]
|
||||
_ = x[actBgTransformFooterLabel-123]
|
||||
_ = x[actBgTransformInputLabel-124]
|
||||
_ = x[actBgTransformListLabel-125]
|
||||
_ = x[actBgTransformNth-126]
|
||||
_ = x[actBgTransformPointer-127]
|
||||
_ = x[actBgTransformPreviewLabel-128]
|
||||
_ = x[actBgTransformPrompt-129]
|
||||
_ = x[actBgTransformQuery-130]
|
||||
_ = x[actBgTransformSearch-131]
|
||||
_ = x[actBgCancel-132]
|
||||
_ = x[actSearch-133]
|
||||
_ = x[actPreview-134]
|
||||
_ = x[actPreviewTop-135]
|
||||
_ = x[actPreviewBottom-136]
|
||||
_ = x[actPreviewUp-137]
|
||||
_ = x[actPreviewDown-138]
|
||||
_ = x[actPreviewPageUp-139]
|
||||
_ = x[actPreviewPageDown-140]
|
||||
_ = x[actPreviewHalfPageUp-141]
|
||||
_ = x[actPreviewHalfPageDown-142]
|
||||
_ = x[actPrevHistory-143]
|
||||
_ = x[actPrevSelected-144]
|
||||
_ = x[actPrint-145]
|
||||
_ = x[actPut-146]
|
||||
_ = x[actNextHistory-147]
|
||||
_ = x[actNextSelected-148]
|
||||
_ = x[actExecute-149]
|
||||
_ = x[actExecuteSilent-150]
|
||||
_ = x[actExecuteMulti-151]
|
||||
_ = x[actSigStop-152]
|
||||
_ = x[actBest-153]
|
||||
_ = x[actFirst-154]
|
||||
_ = x[actLast-155]
|
||||
_ = x[actReload-156]
|
||||
_ = x[actReloadSync-157]
|
||||
_ = x[actDisableSearch-158]
|
||||
_ = x[actEnableSearch-159]
|
||||
_ = x[actSelect-160]
|
||||
_ = x[actDeselect-161]
|
||||
_ = x[actUnbind-162]
|
||||
_ = x[actRebind-163]
|
||||
_ = x[actToggleBind-164]
|
||||
_ = x[actBecome-165]
|
||||
_ = x[actShowHeader-166]
|
||||
_ = x[actHideHeader-167]
|
||||
_ = x[actBell-168]
|
||||
_ = x[actExclude-169]
|
||||
_ = x[actExcludeMulti-170]
|
||||
_ = x[actAsync-171]
|
||||
}
|
||||
|
||||
const _actionType_name = "actIgnoreactStartactClickactInvalidactBracketedPasteBeginactBracketedPasteEndactCharactMouseactBeginningOfLineactAbortactAcceptactAcceptNonEmptyactAcceptOrPrintQueryactBackwardCharactBackwardDeleteCharactBackwardDeleteCharEofactBackwardWordactBackwardSubWordactCancelactChangeBorderLabelactChangeGhostactChangeHeaderactChangeFooteractChangeHeaderLabelactChangeFooterLabelactChangeInputLabelactChangeListLabelactChangeMultiactChangeNthactChangePointeractChangePreviewactChangePreviewLabelactChangePreviewWindowactChangePromptactChangeQueryactClearScreenactClearQueryactClearSelectionactCloseactDeleteCharactDeleteCharEofactEndOfLineactFatalactForwardCharactForwardWordactForwardSubWordactKillLineactKillWordactKillSubWordactUnixLineDiscardactUnixWordRuboutactYankactBackwardKillWordactBackwardKillSubWordactSelectAllactDeselectAllactToggleactToggleSearchactToggleAllactToggleDownactToggleUpactToggleInactToggleOutactToggleTrackactToggleTrackCurrentactToggleHeaderactToggleWrapactToggleMultiLineactToggleHscrollactToggleRawactEnableRawactDisableRawactTrackCurrentactToggleInputactHideInputactShowInputactUntrackCurrentactDownactDownMatchactUpactUpMatchactPageUpactPageDownactPositionactHalfPageUpactHalfPageDownactOffsetUpactOffsetDownactOffsetMiddleactJumpactJumpAcceptactPrintQueryactRefreshPreviewactReplaceQueryactToggleSortactShowPreviewactHidePreviewactTogglePreviewactTogglePreviewWrapactTogglePreviewWrapWordactTransformactTransformBorderLabelactTransformGhostactTransformHeaderactTransformFooteractTransformHeaderLabelactTransformFooterLabelactTransformInputLabelactTransformListLabelactTransformNthactTransformPointeractTransformPreviewLabelactTransformPromptactTransformQueryactTransformSearchactTriggeractBgTransformactBgTransformBorderLabelactBgTransformGhostactBgTransformHeaderactBgTransformFooteractBgTransformHeaderLabelactBgTransformFooterLabelactBgTransformInputLabelactBgTransformListLabelactBgTransformNthactBgTransformPointeractBgTransformPreviewLabelactBgTransformPromptactBgTransformQueryactBgTransformSearchactBgCancelactSearchactPreviewactPreviewTopactPreviewBottomactPreviewUpactPreviewDownactPreviewPageUpactPreviewPageDownactPreviewHalfPageUpactPreviewHalfPageDownactPrevHistoryactPrevSelectedactPrintactPutactNextHistoryactNextSelectedactExecuteactExecuteSilentactExecuteMultiactSigStopactBestactFirstactLastactReloadactReloadSyncactDisableSearchactEnableSearchactSelectactDeselectactUnbindactRebindactToggleBindactBecomeactShowHeaderactHideHeaderactBellactExcludeactExcludeMultiactAsync"
|
||||
const _actionType_name = "actIgnoreactStartactClickactInvalidactBracketedPasteBeginactBracketedPasteEndactCharactMouseactBeginningOfLineactAbortactAcceptactAcceptNonEmptyactAcceptOrPrintQueryactBackwardCharactBackwardDeleteCharactBackwardDeleteCharEofactBackwardWordactBackwardSubWordactCancelactChangeBorderLabelactChangeGhostactChangeHeaderactChangeFooteractChangeHeaderLabelactChangeFooterLabelactChangeInputLabelactChangeListLabelactChangeMultiactChangeNthactChangePointeractChangePreviewactChangePreviewLabelactChangePreviewWindowactChangePromptactChangeQueryactClearScreenactClearQueryactClearSelectionactCloseactDeleteCharactDeleteCharEofactEndOfLineactFatalactForwardCharactForwardWordactForwardSubWordactKillLineactKillWordactKillSubWordactUnixLineDiscardactUnixWordRuboutactYankactBackwardKillWordactBackwardKillSubWordactSelectAllactDeselectAllactToggleactToggleSearchactToggleAllactToggleDownactToggleUpactToggleInactToggleOutactToggleTrackactToggleTrackCurrentactToggleHeaderactToggleWrapactToggleWrapWordactToggleMultiLineactToggleHscrollactToggleRawactEnableRawactDisableRawactTrackCurrentactToggleInputactHideInputactShowInputactUntrackCurrentactDownactDownMatchactUpactUpMatchactPageUpactPageDownactPositionactHalfPageUpactHalfPageDownactOffsetUpactOffsetDownactOffsetMiddleactJumpactJumpAcceptactPrintQueryactRefreshPreviewactReplaceQueryactToggleSortactShowPreviewactHidePreviewactTogglePreviewactTogglePreviewWrapactTogglePreviewWrapWordactTransformactTransformBorderLabelactTransformGhostactTransformHeaderactTransformFooteractTransformHeaderLabelactTransformFooterLabelactTransformInputLabelactTransformListLabelactTransformNthactTransformPointeractTransformPreviewLabelactTransformPromptactTransformQueryactTransformSearchactTriggeractBgTransformactBgTransformBorderLabelactBgTransformGhostactBgTransformHeaderactBgTransformFooteractBgTransformHeaderLabelactBgTransformFooterLabelactBgTransformInputLabelactBgTransformListLabelactBgTransformNthactBgTransformPointeractBgTransformPreviewLabelactBgTransformPromptactBgTransformQueryactBgTransformSearchactBgCancelactSearchactPreviewactPreviewTopactPreviewBottomactPreviewUpactPreviewDownactPreviewPageUpactPreviewPageDownactPreviewHalfPageUpactPreviewHalfPageDownactPrevHistoryactPrevSelectedactPrintactPutactNextHistoryactNextSelectedactExecuteactExecuteSilentactExecuteMultiactSigStopactBestactFirstactLastactReloadactReloadSyncactDisableSearchactEnableSearchactSelectactDeselectactUnbindactRebindactToggleBindactBecomeactShowHeaderactHideHeaderactBellactExcludeactExcludeMultiactAsync"
|
||||
|
||||
var _actionType_index = [...]uint16{0, 9, 17, 25, 35, 57, 77, 84, 92, 110, 118, 127, 144, 165, 180, 201, 225, 240, 258, 267, 287, 301, 316, 331, 351, 371, 390, 408, 422, 434, 450, 466, 487, 509, 524, 538, 552, 565, 582, 590, 603, 619, 631, 639, 653, 667, 684, 695, 706, 720, 738, 755, 762, 781, 803, 815, 829, 838, 853, 865, 878, 889, 900, 912, 926, 947, 962, 975, 993, 1009, 1021, 1033, 1046, 1061, 1075, 1087, 1099, 1116, 1123, 1135, 1140, 1150, 1159, 1170, 1181, 1194, 1209, 1220, 1233, 1248, 1255, 1268, 1281, 1298, 1313, 1326, 1340, 1354, 1370, 1390, 1414, 1426, 1449, 1466, 1484, 1502, 1525, 1548, 1570, 1591, 1606, 1625, 1649, 1667, 1684, 1702, 1712, 1726, 1751, 1770, 1790, 1810, 1835, 1860, 1884, 1907, 1924, 1945, 1971, 1991, 2010, 2030, 2041, 2050, 2060, 2073, 2089, 2101, 2115, 2131, 2149, 2169, 2191, 2205, 2220, 2228, 2234, 2248, 2263, 2273, 2289, 2304, 2314, 2321, 2329, 2336, 2345, 2358, 2374, 2389, 2398, 2409, 2418, 2427, 2440, 2449, 2462, 2475, 2482, 2492, 2507, 2515}
|
||||
var _actionType_index = [...]uint16{0, 9, 17, 25, 35, 57, 77, 84, 92, 110, 118, 127, 144, 165, 180, 201, 225, 240, 258, 267, 287, 301, 316, 331, 351, 371, 390, 408, 422, 434, 450, 466, 487, 509, 524, 538, 552, 565, 582, 590, 603, 619, 631, 639, 653, 667, 684, 695, 706, 720, 738, 755, 762, 781, 803, 815, 829, 838, 853, 865, 878, 889, 900, 912, 926, 947, 962, 975, 992, 1010, 1026, 1038, 1050, 1063, 1078, 1092, 1104, 1116, 1133, 1140, 1152, 1157, 1167, 1176, 1187, 1198, 1211, 1226, 1237, 1250, 1265, 1272, 1285, 1298, 1315, 1330, 1343, 1357, 1371, 1387, 1407, 1431, 1443, 1466, 1483, 1501, 1519, 1542, 1565, 1587, 1608, 1623, 1642, 1666, 1684, 1701, 1719, 1729, 1743, 1768, 1787, 1807, 1827, 1852, 1877, 1901, 1924, 1941, 1962, 1988, 2008, 2027, 2047, 2058, 2067, 2077, 2090, 2106, 2118, 2132, 2148, 2166, 2186, 2208, 2222, 2237, 2245, 2251, 2265, 2280, 2290, 2306, 2321, 2331, 2338, 2346, 2353, 2362, 2375, 2391, 2406, 2415, 2426, 2435, 2444, 2457, 2466, 2479, 2492, 2499, 2509, 2524, 2532}
|
||||
|
||||
func (i actionType) String() string {
|
||||
if i < 0 || i >= actionType(len(_actionType_index)-1) {
|
||||
|
||||
@@ -95,7 +95,7 @@ Usage: fzf [options]
|
||||
-m, --multi[=MAX] Enable multi-select with tab/shift-tab
|
||||
--highlight-line Highlight the whole current line
|
||||
--cycle Enable cyclic scroll
|
||||
--wrap Enable line wrap
|
||||
--wrap[=MODE] Enable line wrap (char|word, default: char)
|
||||
--wrap-sign=STR Indicator for wrapped lines
|
||||
--no-multi-line Disable multi-line display of items when using --read0
|
||||
--raw Enable raw mode (show non-matching items)
|
||||
@@ -606,6 +606,7 @@ type Options struct {
|
||||
Layout layoutType
|
||||
Cycle bool
|
||||
Wrap bool
|
||||
WrapWord bool
|
||||
WrapSign *string
|
||||
MultiLine bool
|
||||
CursorLine bool
|
||||
@@ -740,6 +741,7 @@ func defaultOptions() *Options {
|
||||
Layout: layoutDefault,
|
||||
Cycle: false,
|
||||
Wrap: false,
|
||||
WrapWord: false,
|
||||
MultiLine: true,
|
||||
KeepRight: false,
|
||||
Hscroll: true,
|
||||
@@ -1804,6 +1806,8 @@ func parseActionList(masked string, original string, prevActions []*action, putA
|
||||
appendAction(actToggleHeader)
|
||||
case "toggle-wrap":
|
||||
appendAction(actToggleWrap)
|
||||
case "toggle-wrap-word":
|
||||
appendAction(actToggleWrapWord)
|
||||
case "toggle-multi-line":
|
||||
appendAction(actToggleMultiLine)
|
||||
case "toggle-hscroll":
|
||||
@@ -2853,9 +2857,29 @@ func parseOptions(index *int, opts *Options, allArgs []string) error {
|
||||
case "--no-cycle":
|
||||
opts.Cycle = false
|
||||
case "--wrap":
|
||||
opts.Wrap = true
|
||||
given, str := optionalNextString()
|
||||
if given {
|
||||
switch str {
|
||||
case "char":
|
||||
opts.Wrap = true
|
||||
opts.WrapWord = false
|
||||
case "word":
|
||||
opts.Wrap = true
|
||||
opts.WrapWord = true
|
||||
default:
|
||||
return errors.New("invalid wrap mode: " + str + " (expected: char or word)")
|
||||
}
|
||||
} else {
|
||||
opts.Wrap = true
|
||||
}
|
||||
case "--no-wrap":
|
||||
opts.Wrap = false
|
||||
opts.WrapWord = false
|
||||
case "--wrap-word":
|
||||
opts.Wrap = true
|
||||
opts.WrapWord = true
|
||||
case "--no-wrap-word":
|
||||
opts.WrapWord = false
|
||||
case "--wrap-sign":
|
||||
str, err := nextString("wrap sign required")
|
||||
if err != nil {
|
||||
|
||||
@@ -250,6 +250,7 @@ type Terminal struct {
|
||||
infoStyle infoStyle
|
||||
infoPrefix string
|
||||
wrap bool
|
||||
wrapWord bool
|
||||
wrapSign string
|
||||
wrapSignWidth int
|
||||
ghost string
|
||||
@@ -585,6 +586,7 @@ const (
|
||||
actToggleTrackCurrent
|
||||
actToggleHeader
|
||||
actToggleWrap
|
||||
actToggleWrapWord
|
||||
actToggleMultiLine
|
||||
actToggleHscroll
|
||||
actToggleRaw
|
||||
@@ -830,8 +832,8 @@ func defaultKeymap() map[tui.Event][]*action {
|
||||
if !util.IsWindows() {
|
||||
add(tui.CtrlZ, actSigStop)
|
||||
}
|
||||
add(tui.CtrlSlash, actToggleWrap)
|
||||
addEvent(tui.AltKey('/'), actToggleWrap)
|
||||
add(tui.CtrlSlash, actToggleWrapWord)
|
||||
addEvent(tui.AltKey('/'), actToggleWrapWord)
|
||||
|
||||
addEvent(tui.AltKey('b'), actBackwardWord)
|
||||
add(tui.ShiftLeft, actBackwardWord)
|
||||
@@ -1014,6 +1016,7 @@ func NewTerminal(opts *Options, eventBox *util.EventBox, executor *util.Executor
|
||||
multi: opts.Multi,
|
||||
multiLine: opts.ReadZero && opts.MultiLine,
|
||||
wrap: opts.Wrap,
|
||||
wrapWord: opts.WrapWord,
|
||||
sort: opts.Sort > 0,
|
||||
toggleSort: opts.ToggleSort,
|
||||
track: opts.Track,
|
||||
@@ -1635,7 +1638,7 @@ func (t *Terminal) numItemLines(item *Item, atMost int) (int, bool) {
|
||||
numLines, overflow = item.text.NumLines(atMost)
|
||||
} else {
|
||||
var lines [][]rune
|
||||
lines, overflow = item.text.Lines(t.multiLine, atMost, t.wrapCols(), t.wrapSignWidth, t.tabstop)
|
||||
lines, overflow = item.text.Lines(t.multiLine, atMost, t.wrapCols(), t.wrapSignWidth, t.tabstop, t.wrapWord)
|
||||
numLines = len(lines)
|
||||
}
|
||||
numLines += t.gap
|
||||
@@ -1651,7 +1654,7 @@ func (t *Terminal) itemLines(item *Item, atMost int) ([][]rune, bool) {
|
||||
copy(text, item.text.ToRunes())
|
||||
return [][]rune{text}, false
|
||||
}
|
||||
return item.text.Lines(t.multiLine, atMost, t.wrapCols(), t.wrapSignWidth, t.tabstop)
|
||||
return item.text.Lines(t.multiLine, atMost, t.wrapCols(), t.wrapSignWidth, t.tabstop, t.wrapWord)
|
||||
}
|
||||
|
||||
// Estimate the average number of lines per item. Instead of going through all
|
||||
@@ -6721,8 +6724,16 @@ func (t *Terminal) Loop() error {
|
||||
case actToggleHeader:
|
||||
t.headerVisible = !t.headerVisible
|
||||
req(reqList, reqInfo, reqPrompt, reqHeader)
|
||||
case actToggleWrap:
|
||||
t.wrap = !t.wrap
|
||||
case actToggleWrap, actToggleWrapWord:
|
||||
if a.t == actToggleWrapWord {
|
||||
t.wrapWord = !t.wrapWord
|
||||
t.wrap = t.wrapWord
|
||||
} else {
|
||||
t.wrap = !t.wrap
|
||||
if !t.wrap {
|
||||
t.wrapWord = false
|
||||
}
|
||||
}
|
||||
t.clearNumLinesCache()
|
||||
req(reqList, reqHeader)
|
||||
case actToggleMultiLine:
|
||||
|
||||
@@ -249,7 +249,7 @@ func (chars *Chars) Prepend(prefix string) {
|
||||
}
|
||||
}
|
||||
|
||||
func (chars *Chars) Lines(multiLine bool, maxLines int, wrapCols int, wrapSignWidth int, tabstop int) ([][]rune, bool) {
|
||||
func (chars *Chars) Lines(multiLine bool, maxLines int, wrapCols int, wrapSignWidth int, tabstop int, wrapWord bool) ([][]rune, bool) {
|
||||
text := make([]rune, chars.Length())
|
||||
copy(text, chars.ToRunes())
|
||||
|
||||
@@ -307,6 +307,19 @@ func (chars *Chars) Lines(multiLine bool, maxLines int, wrapCols int, wrapSignWi
|
||||
if overflowIdx == 0 {
|
||||
overflowIdx = 1
|
||||
}
|
||||
if wrapWord {
|
||||
// Find last space/tab at or before overflowIdx
|
||||
breakIdx := -1
|
||||
for k := overflowIdx; k > 0; k-- {
|
||||
if line[k-1] == ' ' || line[k-1] == '\t' {
|
||||
breakIdx = k
|
||||
break
|
||||
}
|
||||
}
|
||||
if breakIdx > 0 {
|
||||
overflowIdx = breakIdx
|
||||
}
|
||||
}
|
||||
if len(wrapped) >= maxLines {
|
||||
return wrapped, true
|
||||
}
|
||||
|
||||
@@ -51,7 +51,7 @@ func TestTrimLength(t *testing.T) {
|
||||
func TestCharsLines(t *testing.T) {
|
||||
chars := ToChars([]byte("abcdef\n가나다\n\tdef"))
|
||||
check := func(multiLine bool, maxLines int, wrapCols int, wrapSignWidth int, tabstop int, expectedNumLines int, expectedOverflow bool) {
|
||||
lines, overflow := chars.Lines(multiLine, maxLines, wrapCols, wrapSignWidth, tabstop)
|
||||
lines, overflow := chars.Lines(multiLine, maxLines, wrapCols, wrapSignWidth, tabstop, false)
|
||||
fmt.Println(lines, overflow)
|
||||
if len(lines) != expectedNumLines || overflow != expectedOverflow {
|
||||
t.Errorf("Invalid result: %d %v (expected %d %v)", len(lines), overflow, expectedNumLines, expectedOverflow)
|
||||
@@ -81,3 +81,51 @@ func TestCharsLines(t *testing.T) {
|
||||
// With wrap sign (3 + 2) and no multi-line
|
||||
check(false, 100, 3, 2, 1, 13, false)
|
||||
}
|
||||
|
||||
func TestCharsLinesWrapWord(t *testing.T) {
|
||||
// "hello world foo bar" with width 12 should break at word boundaries
|
||||
chars := ToChars([]byte("hello world foo bar"))
|
||||
lines, overflow := chars.Lines(false, 100, 12, 0, 8, true)
|
||||
// "hello world " (12) | "foo bar" (7)
|
||||
if len(lines) != 2 || overflow {
|
||||
t.Errorf("Expected 2 lines, got %d (overflow: %v): %v", len(lines), overflow, lines)
|
||||
}
|
||||
if string(lines[0]) != "hello world " {
|
||||
t.Errorf("Expected first line 'hello world ', got %q", string(lines[0]))
|
||||
}
|
||||
if string(lines[1]) != "foo bar" {
|
||||
t.Errorf("Expected second line 'foo bar', got %q", string(lines[1]))
|
||||
}
|
||||
|
||||
// No word boundary: a single long word falls back to character wrap
|
||||
chars2 := ToChars([]byte("abcdefghijklmnop"))
|
||||
lines2, _ := chars2.Lines(false, 100, 10, 0, 8, true)
|
||||
if len(lines2) != 2 {
|
||||
t.Errorf("Expected 2 lines for long word, got %d: %v", len(lines2), lines2)
|
||||
}
|
||||
if string(lines2[0]) != "abcdefghij" {
|
||||
t.Errorf("Expected first line 'abcdefghij', got %q", string(lines2[0]))
|
||||
}
|
||||
|
||||
// Tab as word boundary
|
||||
chars3 := ToChars([]byte("hello\tworld"))
|
||||
lines3, _ := chars3.Lines(false, 100, 7, 0, 8, true)
|
||||
// "hello\t" should break at tab (width of tab at pos 5 with tabstop 8 = 3, total width = 8 > 7)
|
||||
// Actually RunesWidth: 'h'=1,'e'=1,'l'=1,'l'=1,'o'=1,'\t'=3 = 8 > 7, overflowIdx=5
|
||||
// Then word-wrap scans back and finds no space/tab before idx 5 (tab IS at idx 5 but we check line[k-1])
|
||||
// Wait - let me think: overflowIdx=5, we check k=5 -> line[4]='o', k=4 -> line[3]='l'... no space/tab found
|
||||
// Falls back to character wrap: "hello" | "\tworld"
|
||||
if len(lines3) < 2 {
|
||||
t.Errorf("Expected at least 2 lines for tab test, got %d: %v", len(lines3), lines3)
|
||||
}
|
||||
|
||||
// wrapWord=false still character-wraps
|
||||
chars4 := ToChars([]byte("hello world"))
|
||||
lines4, _ := chars4.Lines(false, 100, 8, 0, 8, false)
|
||||
if len(lines4) != 2 {
|
||||
t.Errorf("Expected 2 lines with wrapWord=false, got %d: %v", len(lines4), lines4)
|
||||
}
|
||||
if string(lines4[0]) != "hello wo" {
|
||||
t.Errorf("Expected first line 'hello wo', got %q", string(lines4[0]))
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user