burterm/internal/tui/style.go
2026-09-14 10:55:07 +03:00

110 lines
4.5 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package tui
import (
"net/http"
"strings"
"github.com/charmbracelet/lipgloss"
"github.com/r3g1tpr0cs/burterm/internal/project"
"github.com/r3g1tpr0cs/burterm/internal/scanner"
)
// Цвета подобраны по классам HTTP-статуса — тот же принцип, что и
// цветовая маркировка в Burp: 2xx зелёный, 3xx голубой, 4xx жёлтый,
// 5xx красный. Сетевые ошибки (таймаут, обрыв соединения — не HTTP-
// статус вовсе) получают отдельный цвет, чтобы не путать с 5xx.
var (
style2xx = lipgloss.NewStyle().Foreground(lipgloss.Color("42"))
style3xx = lipgloss.NewStyle().Foreground(lipgloss.Color("51"))
style4xx = lipgloss.NewStyle().Foreground(lipgloss.Color("220"))
style5xx = lipgloss.NewStyle().Foreground(lipgloss.Color("196"))
styleErrStatus = lipgloss.NewStyle().Foreground(lipgloss.Color("201"))
styleDim = lipgloss.NewStyle().Foreground(lipgloss.Color("245"))
// styleHighlight — единый стиль для строк, подпавших под пользовательское
// regex-правило подсветки. Намеренно НЕ комбинируется с statusStyle на
// одной строке: lipgloss.Style.Render оборачивает текст кодами
// ESC[...]...ESC[0m, а ESC[0m сбрасывает вообще все атрибуты, включая
// внешние — если вложить один Render внутрь другого, первый же
// внутренний сброс "съест" стиль снаружи для остатка строки. Поэтому
// для подсвеченных строк весь рендер идёт через один-единственный
// styleHighlight, без отдельной раскраски статуса внутри.
styleHighlight = lipgloss.NewStyle().Bold(true).Background(lipgloss.Color("58")).Foreground(lipgloss.Color("230"))
)
// statusStyle подбирает стиль по классу статус-кода.
func statusStyle(code int) lipgloss.Style {
switch {
case code >= 200 && code < 300:
return style2xx
case code >= 300 && code < 400:
return style3xx
case code >= 400 && code < 500:
return style4xx
case code >= 500 && code < 600:
return style5xx
default:
return styleDim
}
}
// colorLabelStyle раскрашивает пользовательскую цветовую метку проекта
// (project.ColorLabel) в её собственный цвет — не путать с statusStyle,
// которая красит по автоматическому классу HTTP-статуса: это разные
// вещи, метка выставляется руками (клавиша "c" на вкладке Project).
func colorLabelStyle(c project.ColorLabel) lipgloss.Style {
switch c {
case project.ColorRed:
return lipgloss.NewStyle().Foreground(lipgloss.Color("196"))
case project.ColorOrange:
return lipgloss.NewStyle().Foreground(lipgloss.Color("208"))
case project.ColorYellow:
return lipgloss.NewStyle().Foreground(lipgloss.Color("220"))
case project.ColorGreen:
return lipgloss.NewStyle().Foreground(lipgloss.Color("42"))
case project.ColorCyan:
return lipgloss.NewStyle().Foreground(lipgloss.Color("51"))
case project.ColorBlue:
return lipgloss.NewStyle().Foreground(lipgloss.Color("33"))
case project.ColorPurple:
return lipgloss.NewStyle().Foreground(lipgloss.Color("129"))
default:
return styleDim
}
}
// severityStyle подбирает стиль для находок Scanner — переиспользует
// ту же цветовую шкалу, что и statusStyle, просто с другим входом.
func severityStyle(sev scanner.Severity) lipgloss.Style {
switch sev {
case scanner.SeverityHigh:
return style5xx
case scanner.SeverityMedium:
return style4xx
case scanner.SeverityLow:
return style3xx
default:
return styleDim
}
}
// contentTypeLabel вытаскивает короткую метку типа контента из заголовка
// Content-Type: "application/json; charset=utf-8" → "json".
func contentTypeLabel(h http.Header) string {
if h == nil {
return ""
}
ct := h.Get("Content-Type")
if ct == "" {
return ""
}
if idx := strings.Index(ct, ";"); idx != -1 {
ct = ct[:idx]
}
ct = strings.TrimSpace(ct)
if idx := strings.LastIndex(ct, "/"); idx != -1 {
return ct[idx+1:]
}
return ct
}