|
38 | 38 | // is passed to tea.NewProgram() which accepts tea.Model |
39 | 39 | // Either way type 'model' is not exported, so there is not way main package can |
40 | 40 | // be aware of it, and use it directly |
41 | | -func InitialModel(firstFilePanelDirs []string, firstUseCheck bool) tea.Model { |
42 | | - toggleDotFile, toggleFooter, zClient := initialConfig(firstFilePanelDirs) |
43 | | - return defaultModelConfig(toggleDotFile, toggleFooter, firstUseCheck, firstFilePanelDirs, zClient) |
| 41 | +func InitialModel(firstPanelPaths []string, firstUseCheck bool) tea.Model { |
| 42 | + toggleDotFile, toggleFooter, zClient := initialConfig(firstPanelPaths) |
| 43 | + return defaultModelConfig(toggleDotFile, toggleFooter, firstUseCheck, firstPanelPaths, zClient) |
44 | 44 | } |
45 | 45 |
|
46 | 46 | // Init function to be called by Bubble tea framework, sets windows title, |
@@ -696,50 +696,75 @@ func getMaxW(s string) int { |
696 | 696 | // Render and update file panel items. Check for changes and updates in files and |
697 | 697 | // folders in the current directory. |
698 | 698 | func (m *model) getFilePanelItems() { |
699 | | - focusPanel := m.fileModel.filePanels[m.filePanelFocusIndex] |
700 | | - for i, filePanel := range m.fileModel.filePanels { |
701 | | - var fileElement []element |
| 699 | + focusPanel := &m.fileModel.filePanels[m.filePanelFocusIndex] |
| 700 | + for i := range m.fileModel.filePanels { |
| 701 | + filePanel := &m.fileModel.filePanels[i] |
702 | 702 | nowTime := time.Now() |
703 | | - // Check last time each element was updated, if less then 3 seconds ignore |
704 | | - if !filePanel.isFocused && nowTime.Sub(filePanel.lastTimeGetElement) < 3*time.Second { |
705 | | - // TODO : revisit this. This feels like a duct tape solution of an actual |
706 | | - // deep rooted problem. This feels very hacky. |
707 | | - if !m.updatedToggleDotFile { |
708 | | - continue |
| 703 | + if !m.shouldSkipPanelUpdate(filePanel, focusPanel, nowTime) { |
| 704 | + // Load elements for this panel (with/without search filter) |
| 705 | + filePanel.element = m.getElementsForPanel(filePanel) |
| 706 | + // Update file panel list |
| 707 | + filePanel.lastTimeGetElement = nowTime |
| 708 | + |
| 709 | + // For hover to file on first time loading |
| 710 | + if filePanel.targetFile != "" { |
| 711 | + filePanel.applyTargetFileCursor() |
709 | 712 | } |
710 | 713 | } |
| 714 | + // Due to applyTargetFileCursor, cursor might go out of range |
| 715 | + filePanel.scrollToCursor(m.mainPanelHeight) |
| 716 | + } |
711 | 717 |
|
712 | | - focusPanelReRender := false |
| 718 | + m.updatedToggleDotFile = false |
| 719 | +} |
713 | 720 |
|
714 | | - if len(focusPanel.element) > 0 { |
715 | | - if filepath.Dir(focusPanel.element[0].location) != focusPanel.location { |
716 | | - focusPanelReRender = true |
717 | | - } |
718 | | - } else { |
719 | | - focusPanelReRender = true |
| 721 | +// Helper to decide whether to skip updating a panel this tick. |
| 722 | +func (m *model) shouldSkipPanelUpdate(filePanel *filePanel, focusPanel *filePanel, nowTime time.Time) bool { |
| 723 | + // Throttle non-focused panels unless dotfile toggle changed |
| 724 | + if !filePanel.isFocused && nowTime.Sub(filePanel.lastTimeGetElement) < 3*time.Second { |
| 725 | + if !m.updatedToggleDotFile { |
| 726 | + return true |
720 | 727 | } |
| 728 | + } |
721 | 729 |
|
722 | | - reRenderTime := int(float64(len(filePanel.element)) / 100) |
| 730 | + focusPanelReRender := focusPanel.needsReRender() |
| 731 | + reRenderTime := int(float64(len(filePanel.element)) / 100) |
| 732 | + if filePanel.isFocused && !focusPanelReRender && |
| 733 | + nowTime.Sub(filePanel.lastTimeGetElement) < time.Duration(reRenderTime)*time.Second { |
| 734 | + return true |
| 735 | + } |
| 736 | + return false |
| 737 | +} |
723 | 738 |
|
724 | | - if filePanel.isFocused && !focusPanelReRender && |
725 | | - nowTime.Sub(filePanel.lastTimeGetElement) < time.Duration(reRenderTime)*time.Second { |
726 | | - continue |
727 | | - } |
| 739 | +// Checks whether the focus panel directory changed and forces a re-render. |
| 740 | +func (panel *filePanel) needsReRender() bool { |
| 741 | + if len(panel.element) > 0 { |
| 742 | + return filepath.Dir(panel.element[0].location) != panel.location |
| 743 | + } |
| 744 | + return true |
| 745 | +} |
728 | 746 |
|
729 | | - // Get file names based on search bar filter |
730 | | - if filePanel.searchBar.Value() != "" { |
731 | | - fileElement = returnDirElementBySearchString(filePanel.location, m.toggleDotFile, |
732 | | - filePanel.searchBar.Value(), filePanel.sortOptions.data) |
733 | | - } else { |
734 | | - fileElement = returnDirElement(filePanel.location, m.toggleDotFile, filePanel.sortOptions.data) |
735 | | - } |
736 | | - // Update file panel list |
737 | | - filePanel.element = fileElement |
738 | | - m.fileModel.filePanels[i].element = fileElement |
739 | | - m.fileModel.filePanels[i].lastTimeGetElement = nowTime |
| 747 | +// Retrieves elements for a panel based on search bar value and sort options. |
| 748 | +func (m *model) getElementsForPanel(filePanel *filePanel) []element { |
| 749 | + if filePanel.searchBar.Value() != "" { |
| 750 | + return returnDirElementBySearchString( |
| 751 | + filePanel.location, |
| 752 | + m.toggleDotFile, |
| 753 | + filePanel.searchBar.Value(), |
| 754 | + filePanel.sortOptions.data, |
| 755 | + ) |
740 | 756 | } |
| 757 | + return returnDirElement(filePanel.location, m.toggleDotFile, filePanel.sortOptions.data) |
| 758 | +} |
741 | 759 |
|
742 | | - m.updatedToggleDotFile = false |
| 760 | +// Applies targetFile cursor positioning, if configured for the panel. |
| 761 | +func (panel *filePanel) applyTargetFileCursor() { |
| 762 | + for idx, el := range panel.element { |
| 763 | + if el.name == panel.targetFile { |
| 764 | + panel.cursor = idx |
| 765 | + } |
| 766 | + } |
| 767 | + panel.targetFile = "" |
743 | 768 | } |
744 | 769 |
|
745 | 770 | // Close superfile application. Cd into the current dir if CdOnQuit on and save |
|
0 commit comments