| skipped 99 lines |
100 | 100 | | result Result |
101 | 101 | | } |
102 | 102 | | |
| 103 | + | type fitpad struct { |
| 104 | + | fit int |
| 105 | + | pad int |
| 106 | + | } |
| 107 | + | |
103 | 108 | | var emptyLine = itemLine{} |
104 | 109 | | |
105 | 110 | | // Terminal represents terminal input/output |
| skipped 77 lines |
183 | 188 | | prevLines []itemLine |
184 | 189 | | suppress bool |
185 | 190 | | sigstop bool |
186 | | - | startChan chan bool |
| 191 | + | startChan chan fitpad |
187 | 192 | | killChan chan int |
188 | 193 | | slab *util.Slab |
189 | 194 | | theme *tui.ColorTheme |
| skipped 249 lines |
439 | 444 | | return []string{`-`, `\`, `|`, `/`, `-`, `\`, `|`, `/`} |
440 | 445 | | } |
441 | 446 | | |
| 447 | + | func evaluateHeight(opts *Options, termHeight int) int { |
| 448 | + | if opts.Height.percent { |
| 449 | + | return util.Max(int(opts.Height.size*float64(termHeight)/100.0), opts.MinHeight) |
| 450 | + | } |
| 451 | + | return int(opts.Height.size) |
| 452 | + | } |
| 453 | + | |
442 | 454 | | // NewTerminal returns new Terminal object |
443 | 455 | | func NewTerminal(opts *Options, eventBox *util.EventBox) *Terminal { |
444 | 456 | | input := trimQuery(opts.Query) |
| skipped 20 lines |
465 | 477 | | strongAttr = tui.AttrRegular |
466 | 478 | | } |
467 | 479 | | var renderer tui.Renderer |
468 | | - | fullscreen := opts.Height.size == 0 || opts.Height.percent && opts.Height.size == 100 |
| 480 | + | fullscreen := !opts.Height.auto && (opts.Height.size == 0 || opts.Height.percent && opts.Height.size == 100) |
469 | 481 | | if fullscreen { |
470 | 482 | | if tui.HasFullscreenRenderer() { |
471 | 483 | | renderer = tui.NewFullscreenRenderer(opts.Theme, opts.Black, opts.Mouse) |
| skipped 3 lines |
475 | 487 | | } |
476 | 488 | | } else { |
477 | 489 | | maxHeightFunc := func(termHeight int) int { |
478 | | - | var maxHeight int |
479 | | - | if opts.Height.percent { |
480 | | - | maxHeight = util.Max(int(opts.Height.size*float64(termHeight)/100.0), opts.MinHeight) |
481 | | - | } else { |
482 | | - | maxHeight = int(opts.Height.size) |
483 | | - | } |
484 | | - | |
| 490 | + | // Minimum height required to render fzf excluding margin and padding |
485 | 491 | | effectiveMinHeight := minHeight |
486 | | - | if previewBox != nil && (opts.Preview.position == posUp || opts.Preview.position == posDown) { |
487 | | - | effectiveMinHeight *= 2 |
| 492 | + | if previewBox != nil && opts.Preview.aboveOrBelow() { |
| 493 | + | effectiveMinHeight += 1 + borderLines(opts.Preview.border) |
488 | 494 | | } |
489 | 495 | | if opts.InfoStyle != infoDefault { |
490 | 496 | | effectiveMinHeight-- |
491 | 497 | | } |
492 | | - | if opts.BorderShape != tui.BorderNone { |
493 | | - | effectiveMinHeight += 2 |
494 | | - | } |
495 | | - | return util.Min(termHeight, util.Max(maxHeight, effectiveMinHeight)) |
| 498 | + | effectiveMinHeight += borderLines(opts.BorderShape) |
| 499 | + | return util.Min(termHeight, util.Max(evaluateHeight(opts, termHeight), effectiveMinHeight)) |
496 | 500 | | } |
497 | 501 | | renderer = tui.NewLightRenderer(opts.Theme, opts.Black, opts.Mouse, opts.Tabstop, opts.ClearOnExit, false, maxHeightFunc) |
498 | 502 | | } |
| skipped 73 lines |
572 | 576 | | sigstop: false, |
573 | 577 | | slab: util.MakeSlab(slab16Size, slab32Size), |
574 | 578 | | theme: opts.Theme, |
575 | | - | startChan: make(chan bool, 1), |
| 579 | + | startChan: make(chan fitpad, 1), |
576 | 580 | | killChan: make(chan int), |
577 | 581 | | tui: renderer, |
578 | 582 | | initFunc: func() { renderer.Init() }, |
| skipped 8 lines |
587 | 591 | | return &t |
588 | 592 | | } |
589 | 593 | | |
| 594 | + | func borderLines(shape tui.BorderShape) int { |
| 595 | + | switch shape { |
| 596 | + | case tui.BorderHorizontal, tui.BorderRounded, tui.BorderSharp: |
| 597 | + | return 2 |
| 598 | + | case tui.BorderTop, tui.BorderBottom: |
| 599 | + | return 1 |
| 600 | + | } |
| 601 | + | return 0 |
| 602 | + | } |
| 603 | + | |
| 604 | + | // Extra number of lines needed to display fzf |
| 605 | + | func (t *Terminal) extraLines() int { |
| 606 | + | extra := len(t.header0) + t.headerLines + 1 |
| 607 | + | if !t.noInfoLine() { |
| 608 | + | extra++ |
| 609 | + | } |
| 610 | + | return extra |
| 611 | + | } |
| 612 | + | |
| 613 | + | func (t *Terminal) MaxFitAndPad(opts *Options) (int, int) { |
| 614 | + | _, screenHeight, marginInt, paddingInt := t.adjustMarginAndPadding() |
| 615 | + | padHeight := marginInt[0] + marginInt[2] + paddingInt[0] + paddingInt[2] |
| 616 | + | fit := screenHeight - padHeight - t.extraLines() |
| 617 | + | return fit, padHeight |
| 618 | + | } |
| 619 | + | |
590 | 620 | | func (t *Terminal) parsePrompt(prompt string) (func(), int) { |
591 | 621 | | var state *ansiState |
592 | 622 | | trimmed, colors, _ := extractColor(prompt, state, nil) |
| skipped 132 lines |
725 | 755 | | |
726 | 756 | | const ( |
727 | 757 | | minWidth = 4 |
728 | | - | minHeight = 4 |
| 758 | + | minHeight = 3 |
729 | 759 | | ) |
730 | 760 | | |
731 | 761 | | func calculateSize(base int, size sizeSpec, occupied int, minSize int, pad int) int { |
| skipped 4 lines |
736 | 766 | | return util.Constrain(int(size.size)+pad, minSize, max) |
737 | 767 | | } |
738 | 768 | | |
739 | | - | func (t *Terminal) resizeWindows() { |
| 769 | + | func (t *Terminal) adjustMarginAndPadding() (int, int, [4]int, [4]int) { |
740 | 770 | | screenWidth := t.tui.MaxX() |
741 | 771 | | screenHeight := t.tui.MaxY() |
742 | | - | t.prevLines = make([]itemLine, screenHeight) |
743 | | - | |
744 | 772 | | marginInt := [4]int{} // TRBL |
745 | 773 | | paddingInt := [4]int{} // TRBL |
746 | 774 | | sizeSpecToInt := func(index int, spec sizeSpec) int { |
| skipped 42 lines |
789 | 817 | | } |
790 | 818 | | |
791 | 819 | | adjust := func(idx1 int, idx2 int, max int, min int) { |
792 | | - | if max >= min { |
793 | | - | margin := marginInt[idx1] + marginInt[idx2] + paddingInt[idx1] + paddingInt[idx2] |
794 | | - | if max-margin < min { |
795 | | - | desired := max - min |
796 | | - | paddingInt[idx1] = desired * paddingInt[idx1] / margin |
797 | | - | paddingInt[idx2] = desired * paddingInt[idx2] / margin |
798 | | - | marginInt[idx1] = util.Max(extraMargin[idx1], desired*marginInt[idx1]/margin) |
799 | | - | marginInt[idx2] = util.Max(extraMargin[idx2], desired*marginInt[idx2]/margin) |
800 | | - | } |
| 820 | + | if min > max { |
| 821 | + | min = max |
| 822 | + | } |
| 823 | + | margin := marginInt[idx1] + marginInt[idx2] + paddingInt[idx1] + paddingInt[idx2] |
| 824 | + | if max-margin < min { |
| 825 | + | desired := max - min |
| 826 | + | paddingInt[idx1] = desired * paddingInt[idx1] / margin |
| 827 | + | paddingInt[idx2] = desired * paddingInt[idx2] / margin |
| 828 | + | marginInt[idx1] = util.Max(extraMargin[idx1], desired*marginInt[idx1]/margin) |
| 829 | + | marginInt[idx2] = util.Max(extraMargin[idx2], desired*marginInt[idx2]/margin) |
801 | 830 | | } |
802 | 831 | | } |
803 | 832 | | |
804 | 833 | | previewVisible := t.isPreviewEnabled() && t.previewOpts.size.size > 0 |
805 | 834 | | minAreaWidth := minWidth |
806 | 835 | | minAreaHeight := minHeight |
| 836 | + | if t.noInfoLine() { |
| 837 | + | minAreaHeight -= 1 |
| 838 | + | } |
807 | 839 | | if previewVisible { |
| 840 | + | minPreviewHeight := 1 + borderLines(t.previewOpts.border) |
| 841 | + | minPreviewWidth := 5 |
808 | 842 | | switch t.previewOpts.position { |
809 | 843 | | case posUp, posDown: |
810 | | - | minAreaHeight *= 2 |
| 844 | + | minAreaHeight += minPreviewHeight |
| 845 | + | minAreaWidth = util.Max(minPreviewWidth, minAreaWidth) |
811 | 846 | | case posLeft, posRight: |
812 | | - | minAreaWidth *= 2 |
| 847 | + | minAreaWidth += minPreviewWidth |
| 848 | + | minAreaHeight = util.Max(minPreviewHeight, minAreaHeight) |
813 | 849 | | } |
814 | 850 | | } |
815 | 851 | | adjust(1, 3, screenWidth, minAreaWidth) |
816 | 852 | | adjust(0, 2, screenHeight, minAreaHeight) |
| 853 | + | |
| 854 | + | return screenWidth, screenHeight, marginInt, paddingInt |
| 855 | + | } |
| 856 | + | |
| 857 | + | func (t *Terminal) resizeWindows() { |
| 858 | + | screenWidth, screenHeight, marginInt, paddingInt := t.adjustMarginAndPadding() |
| 859 | + | width := screenWidth - marginInt[1] - marginInt[3] |
| 860 | + | height := screenHeight - marginInt[0] - marginInt[2] |
| 861 | + | |
| 862 | + | t.prevLines = make([]itemLine, screenHeight) |
817 | 863 | | if t.border != nil { |
818 | 864 | | t.border.Close() |
819 | 865 | | } |
| skipped 12 lines |
832 | 878 | | // Reset preview version so that full redraw occurs |
833 | 879 | | t.previewed.version = 0 |
834 | 880 | | |
835 | | - | width := screenWidth - marginInt[1] - marginInt[3] |
836 | | - | height := screenHeight - marginInt[0] - marginInt[2] |
837 | 881 | | switch t.borderShape { |
838 | 882 | | case tui.BorderHorizontal: |
839 | 883 | | t.border = t.tui.NewWindow( |
| skipped 25 lines |
865 | 909 | | false, tui.MakeBorderStyle(t.borderShape, t.unicode)) |
866 | 910 | | } |
867 | 911 | | |
868 | | - | // Add padding |
| 912 | + | // Add padding to margin |
869 | 913 | | for idx, val := range paddingInt { |
870 | 914 | | marginInt[idx] += val |
871 | 915 | | } |
872 | | - | width = screenWidth - marginInt[1] - marginInt[3] |
873 | | - | height = screenHeight - marginInt[0] - marginInt[2] |
| 916 | + | width -= paddingInt[1] + paddingInt[3] |
| 917 | + | height -= paddingInt[0] + paddingInt[2] |
874 | 918 | | |
875 | 919 | | // Set up preview window |
| 920 | + | previewVisible := t.isPreviewEnabled() && t.previewOpts.size.size > 0 |
876 | 921 | | noBorder := tui.MakeBorderStyle(tui.BorderNone, t.unicode) |
877 | 922 | | if previewVisible { |
878 | 923 | | var resizePreviewWindows func(previewOpts previewOpts) |
| skipped 1083 lines |
1962 | 2007 | | // Loop is called to start Terminal I/O |
1963 | 2008 | | func (t *Terminal) Loop() { |
1964 | 2009 | | // prof := profile.Start(profile.ProfilePath("/tmp/")) |
1965 | | - | <-t.startChan |
| 2010 | + | fitpad := <-t.startChan |
| 2011 | + | fit := fitpad.fit |
| 2012 | + | if fit >= 0 { |
| 2013 | + | pad := fitpad.pad |
| 2014 | + | t.tui.Resize(func(termHeight int) int { |
| 2015 | + | height := fit + t.extraLines() + pad |
| 2016 | + | if t.hasPreviewer() { |
| 2017 | + | height = util.Max(height, 1+borderLines(t.previewOpts.border)+pad) |
| 2018 | + | } |
| 2019 | + | return util.Min(termHeight, height) |
| 2020 | + | }) |
| 2021 | + | } |
1966 | 2022 | | { // Late initialization |
1967 | 2023 | | intChan := make(chan os.Signal, 1) |
1968 | 2024 | | signal.Notify(intChan, os.Interrupt, syscall.SIGTERM) |
| skipped 970 lines |