@ -170,6 +170,7 @@ type Terminal struct {
selected map [ int32 ] selectedItem
version int64
reqBox * util . EventBox
initialPreviewOpts previewOpts
previewOpts previewOpts
previewer previewer
previewed previewed
@ -286,6 +287,8 @@ const (
actTogglePreview
actTogglePreviewWrap
actPreview
actChangePreview
actChangePreviewWindow
actPreviewTop
actPreviewBottom
actPreviewUp
@ -326,6 +329,7 @@ type searchRequest struct {
type previewRequest struct {
template string
pwindow tui . Window
scrollOffset int
list [ ] * Item
}
@ -416,7 +420,7 @@ func trimQuery(query string) []rune {
func hasPreviewAction ( opts * Options ) bool {
for _ , actions := range opts . Keymap {
for _ , action := range actions {
if action . t == actPreview {
if action . t == actPreview || action . t == actChangePreview {
return true
}
}
@ -547,6 +551,7 @@ func NewTerminal(opts *Options, eventBox *util.EventBox) *Terminal {
merger : EmptyMerger ,
selected : make ( map [ int32 ] selectedItem ) ,
reqBox : util . NewEventBox ( ) ,
initialPreviewOpts : opts . Preview ,
previewOpts : opts . Preview ,
previewer : previewer { 0 , [ ] string { } , 0 , showPreviewWindow , false , true , false , "" } ,
previewed : previewed { 0 , 0 , 0 , false } ,
@ -1642,9 +1647,14 @@ func (t *Terminal) replacePlaceholder(template string, forcePlus bool, input str
template , t . ansi , t . delimiter , t . printsep , forcePlus , input , list )
}
func ( t * Terminal ) evaluateScrollOffset ( list [ ] * Item , height int ) int {
func ( t * Terminal ) evaluateScrollOffset ( ) int {
if t . pwindow == nil {
return 0
}
// We only need the current item to calculate the scroll offset
offsetExpr := offsetTrimCharsRegex . ReplaceAllString (
t . replacePlaceholder ( t . previewOpts . scroll , false , "" , list ) , "" )
t . replacePlaceholder ( t . previewOpts . scroll , false , "" , [ ] * Item { t . currentItem ( ) , nil } ) , "" )
atoi := func ( s string ) int {
n , e := strconv . Atoi ( s )
@ -1655,20 +1665,21 @@ func (t *Terminal) evaluateScrollOffset(list []*Item, height int) int {
}
base := - 1
height := util . Max ( 0 , t . pwindow . Height ( ) - t . previewOpts . headerLines )
for _ , component := range offsetComponentRegex . FindAllString ( offsetExpr , - 1 ) {
if strings . HasPrefix ( component , "-/" ) {
component = component [ 1 : ]
}
if component [ 0 ] == '/' {
denom := atoi ( component [ 1 : ] )
if denom = = 0 {
return base
if denom ! = 0 {
base -= height / denom
}
return base - height / denom
break
}
base += atoi ( component )
}
return base
return util. Max ( 0 , base)
}
func replacePlaceholder ( template string , stripAnsi bool , delimiter Delimiter , printsep string , forcePlus bool , query string , allItems [ ] * Item ) string {
@ -1972,12 +1983,14 @@ func (t *Terminal) Loop() {
var items [ ] * Item
var commandTemplate string
var pwindow tui . Window
initialOffset := 0
t . previewBox . Wait ( func ( events * util . Events ) {
for req , value := range * events {
switch req {
case reqPreviewEnqueue :
request := value . ( previewRequest )
commandTemplate = request . template
initialOffset = request . scrollOffset
items = request . list
pwindow = request . pwindow
}
@ -1989,11 +2002,9 @@ func (t *Terminal) Loop() {
if items [ 0 ] != nil {
_ , query := t . Input ( )
command := t . replacePlaceholder ( commandTemplate , false , string ( query ) , items )
initialOffset := 0
cmd := util . ExecCommand ( command , true )
if pwindow != nil {
height := pwindow . Height ( )
initialOffset = util . Max ( 0 , t . evaluateScrollOffset ( items , util . Max ( 0 , height - t . previewOpts . headerLines ) ) )
env := os . Environ ( )
lines := fmt . Sprintf ( "LINES=%d" , height )
columns := fmt . Sprintf ( "COLUMNS=%d" , pwindow . Width ( ) )
@ -2128,7 +2139,7 @@ func (t *Terminal) Loop() {
if len ( command ) > 0 && t . isPreviewEnabled ( ) {
_ , list := t . buildPlusList ( command , false )
t . cancelPreview ( )
t . previewBox . Set ( reqPreviewEnqueue , previewRequest { command , t . pwindow , list} )
t . previewBox . Set ( reqPreviewEnqueue , previewRequest { command , t . pwindow , t. evaluateScrollOffset ( ) , list} )
}
}
@ -2253,13 +2264,16 @@ func (t *Terminal) Loop() {
}
}
}
togglePreview := func ( enabled bool ) {
togglePreview := func ( enabled bool ) bool {
if t . previewer . enabled != enabled {
t . previewer . enabled = enabled
// We need to immediately update t.pwindow so we don't use reqRedraw
t . tui . Clear ( )
t . resizeWindows ( )
req ( reqPrompt , reqList , reqInfo , reqHeader )
return true
}
return false
}
toggle := func ( ) bool {
current := t . currentItem ( )
@ -2327,7 +2341,7 @@ func (t *Terminal) Loop() {
if valid {
t . cancelPreview ( )
t . previewBox . Set ( reqPreviewEnqueue ,
previewRequest { t . previewOpts . command , t . pwindow , list} )
previewRequest { t . previewOpts . command , t . pwindow , t. evaluateScrollOffset ( ) , list} )
}
}
}
@ -2707,6 +2721,39 @@ func (t *Terminal) Loop() {
for key := range keys {
delete ( t . keymap , key )
}
case actChangePreview :
if t . previewOpts . command != a . a {
togglePreview ( len ( a . a ) > 0 )
t . previewOpts . command = a . a
refreshPreview ( t . previewOpts . command )
}
case actChangePreviewWindow :
currentPreviewOpts := t . previewOpts
// Reset preview options and apply the additional options
t . previewOpts = t . initialPreviewOpts
parsePreviewWindow ( & t . previewOpts , a . a )
if t . previewOpts . hidden {
togglePreview ( false )
} else {
// Full redraw
if ! currentPreviewOpts . sameLayout ( t . previewOpts ) {
if togglePreview ( true ) {
refreshPreview ( t . previewOpts . command )
} else {
req ( reqRedraw )
}
} else if ! currentPreviewOpts . sameContentLayout ( t . previewOpts ) {
t . previewed . version = 0
req ( reqPreviewRefresh )
}
// Adjust scroll offset
if t . hasPreviewWindow ( ) && currentPreviewOpts . scroll != t . previewOpts . scroll {
scrollPreviewTo ( t . evaluateScrollOffset ( ) )
}
}
}
return true
}