forked from Plemya-x/ALR
		
	Initial commit
This commit is contained in:
		
							
								
								
									
										37
									
								
								internal/pager/highlighting.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								internal/pager/highlighting.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,37 @@
 | 
			
		||||
/*
 | 
			
		||||
 * LURE - Linux User REpository
 | 
			
		||||
 * Copyright (C) 2023 Elara Musayelyan
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software: you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU General Public License as published by
 | 
			
		||||
 * the Free Software Foundation, either version 3 of the License, or
 | 
			
		||||
 * (at your option) any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU General Public License
 | 
			
		||||
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
package pager
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"bytes"
 | 
			
		||||
	"io"
 | 
			
		||||
 | 
			
		||||
	"github.com/alecthomas/chroma/v2/quick"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func SyntaxHighlightBash(r io.Reader, style string) (string, error) {
 | 
			
		||||
	data, err := io.ReadAll(r)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return "", err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	w := &bytes.Buffer{}
 | 
			
		||||
	err = quick.Highlight(w, string(data), "bash", "terminal", style)
 | 
			
		||||
	return w.String(), err
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										143
									
								
								internal/pager/pager.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										143
									
								
								internal/pager/pager.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,143 @@
 | 
			
		||||
/*
 | 
			
		||||
 * LURE - Linux User REpository
 | 
			
		||||
 * Copyright (C) 2023 Elara Musayelyan
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software: you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU General Public License as published by
 | 
			
		||||
 * the Free Software Foundation, either version 3 of the License, or
 | 
			
		||||
 * (at your option) any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU General Public License
 | 
			
		||||
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
package pager
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"strings"
 | 
			
		||||
 | 
			
		||||
	"github.com/charmbracelet/bubbles/viewport"
 | 
			
		||||
	tea "github.com/charmbracelet/bubbletea"
 | 
			
		||||
	"github.com/charmbracelet/lipgloss"
 | 
			
		||||
	"github.com/muesli/reflow/wordwrap"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
	titleStyle lipgloss.Style
 | 
			
		||||
	infoStyle  lipgloss.Style
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func init() {
 | 
			
		||||
	b1 := lipgloss.RoundedBorder()
 | 
			
		||||
	b1.Right = "\u251C"
 | 
			
		||||
	titleStyle = lipgloss.NewStyle().BorderStyle(b1).Padding(0, 1)
 | 
			
		||||
 | 
			
		||||
	b2 := lipgloss.RoundedBorder()
 | 
			
		||||
	b2.Left = "\u2524"
 | 
			
		||||
	infoStyle = titleStyle.Copy().BorderStyle(b2)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type Pager struct {
 | 
			
		||||
	model pagerModel
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func New(name, content string) *Pager {
 | 
			
		||||
	return &Pager{
 | 
			
		||||
		model: pagerModel{
 | 
			
		||||
			name:    name,
 | 
			
		||||
			content: content,
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (p *Pager) Run() error {
 | 
			
		||||
	prog := tea.NewProgram(
 | 
			
		||||
		p.model,
 | 
			
		||||
		tea.WithMouseCellMotion(),
 | 
			
		||||
		tea.WithAltScreen(),
 | 
			
		||||
	)
 | 
			
		||||
 | 
			
		||||
	_, err := prog.Run()
 | 
			
		||||
	return err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type pagerModel struct {
 | 
			
		||||
	name     string
 | 
			
		||||
	content  string
 | 
			
		||||
	ready    bool
 | 
			
		||||
	viewport viewport.Model
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (pm pagerModel) Init() tea.Cmd {
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (pm pagerModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
 | 
			
		||||
	var (
 | 
			
		||||
		cmd  tea.Cmd
 | 
			
		||||
		cmds []tea.Cmd
 | 
			
		||||
	)
 | 
			
		||||
 | 
			
		||||
	switch msg := msg.(type) {
 | 
			
		||||
	case tea.KeyMsg:
 | 
			
		||||
		k := msg.String()
 | 
			
		||||
		if k == "ctrl+c" || k == "q" || k == "esc" {
 | 
			
		||||
			return pm, tea.Quit
 | 
			
		||||
		}
 | 
			
		||||
	case tea.WindowSizeMsg:
 | 
			
		||||
		headerHeight := lipgloss.Height(pm.headerView())
 | 
			
		||||
		footerHeight := lipgloss.Height(pm.footerView())
 | 
			
		||||
		verticalMarginHeight := headerHeight + footerHeight
 | 
			
		||||
 | 
			
		||||
		if !pm.ready {
 | 
			
		||||
			pm.viewport = viewport.New(msg.Width, msg.Height-verticalMarginHeight)
 | 
			
		||||
			pm.viewport.HighPerformanceRendering = true
 | 
			
		||||
			pm.viewport.YPosition = headerHeight + 1
 | 
			
		||||
			pm.viewport.SetContent(wordwrap.String(pm.content, msg.Width))
 | 
			
		||||
			pm.ready = true
 | 
			
		||||
		} else {
 | 
			
		||||
			pm.viewport.Width = msg.Width
 | 
			
		||||
			pm.viewport.Height = msg.Height - verticalMarginHeight
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		cmds = append(cmds, viewport.Sync(pm.viewport))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Handle keyboard and mouse events in the viewport
 | 
			
		||||
	pm.viewport, cmd = pm.viewport.Update(msg)
 | 
			
		||||
	cmds = append(cmds, cmd)
 | 
			
		||||
 | 
			
		||||
	return pm, tea.Batch(cmds...)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (pm pagerModel) View() string {
 | 
			
		||||
	if !pm.ready {
 | 
			
		||||
		return "\n  Initializing..."
 | 
			
		||||
	}
 | 
			
		||||
	return fmt.Sprintf("%s\n%s\n%s", pm.headerView(), pm.viewport.View(), pm.footerView())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (pm pagerModel) headerView() string {
 | 
			
		||||
	title := titleStyle.Render(pm.name)
 | 
			
		||||
	line := strings.Repeat("─", max(0, pm.viewport.Width-lipgloss.Width(title)))
 | 
			
		||||
	return lipgloss.JoinHorizontal(lipgloss.Center, title, line)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (pm pagerModel) footerView() string {
 | 
			
		||||
	info := infoStyle.Render(fmt.Sprintf("%3.f%%", pm.viewport.ScrollPercent()*100))
 | 
			
		||||
	line := strings.Repeat("─", max(0, pm.viewport.Width-lipgloss.Width(info)))
 | 
			
		||||
	return lipgloss.JoinHorizontal(lipgloss.Center, line, info)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func max(a, b int) int {
 | 
			
		||||
	if a > b {
 | 
			
		||||
		return a
 | 
			
		||||
	}
 | 
			
		||||
	return b
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user