fix(lint): fix all linting issues

This commit is contained in:
Andrey Nering 2025-04-02 10:52:47 -03:00
commit 41d70ee83b
14 changed files with 94 additions and 87 deletions

View file

@ -39,13 +39,13 @@ var configCmd = &cobra.Command{
c, err := editor.Cmd("Glow", configFile)
if err != nil {
return err
return fmt.Errorf("unable to set config file: %w", err)
}
c.Stdin = os.Stdin
c.Stdout = os.Stdout
c.Stderr = os.Stderr
if err := c.Run(); err != nil {
return err
return fmt.Errorf("unable to run command: %w", err)
}
fmt.Println("Wrote config file to:", configFile)
@ -56,7 +56,7 @@ var configCmd = &cobra.Command{
func ensureConfigFile() error {
if configFile == "" {
configFile = viper.GetViper().ConfigFileUsed()
if err := os.MkdirAll(filepath.Dir(configFile), 0o755); err != nil {
if err := os.MkdirAll(filepath.Dir(configFile), 0o755); err != nil { //nolint:gosec
return fmt.Errorf("could not write configuration file: %w", err)
}
}
@ -69,20 +69,20 @@ func ensureConfigFile() error {
// File doesn't exist yet, create all necessary directories and
// write the default config file
if err := os.MkdirAll(filepath.Dir(configFile), 0o700); err != nil {
return err
return fmt.Errorf("unable create directory: %w", err)
}
f, err := os.Create(configFile)
if err != nil {
return err
return fmt.Errorf("unable to create config file: %w", err)
}
defer func() { _ = f.Close() }()
if _, err := f.WriteString(defaultConfig); err != nil {
return err
return fmt.Errorf("unable to write config file: %w", err)
}
} else if err != nil { // some other error occurred
return err
return fmt.Errorf("unable to stat config file: %w", err)
}
return nil
}

View file

@ -23,29 +23,29 @@ func findGitHubREADME(u *url.URL) (*source, error) {
apiURL := fmt.Sprintf("https://api.%s/repos/%s/%s/readme", u.Hostname(), owner, repo)
// nolint:bodyclose
//nolint:bodyclose
// it is closed on the caller
res, err := http.Get(apiURL) // nolint: gosec
res, err := http.Get(apiURL) //nolint: gosec,noctx
if err != nil {
return nil, err
return nil, fmt.Errorf("unable to get url: %w", err)
}
body, err := io.ReadAll(res.Body)
if err != nil {
return nil, err
return nil, fmt.Errorf("unable to read http response body: %w", err)
}
var result readme
if err := json.Unmarshal(body, &result); err != nil {
return nil, err
return nil, fmt.Errorf("unable to parse json: %w", err)
}
if res.StatusCode == http.StatusOK {
// nolint:bodyclose
//nolint:bodyclose
// it is closed on the caller
resp, err := http.Get(result.DownloadURL)
resp, err := http.Get(result.DownloadURL) //nolint: noctx
if err != nil {
return nil, err
return nil, fmt.Errorf("unable to get url: %w", err)
}
if resp.StatusCode == http.StatusOK {

View file

@ -25,31 +25,31 @@ func findGitLabREADME(u *url.URL) (*source, error) {
apiURL := fmt.Sprintf("https://%s/api/v4/projects/%s", u.Hostname(), projectPath)
// nolint:bodyclose
//nolint:bodyclose
// it is closed on the caller
res, err := http.Get(apiURL) // nolint: gosec
res, err := http.Get(apiURL) //nolint: gosec,noctx
if err != nil {
return nil, err
return nil, fmt.Errorf("unable to get url: %w", err)
}
body, err := io.ReadAll(res.Body)
if err != nil {
return nil, err
return nil, fmt.Errorf("unable to read http response body: %w", err)
}
var result readme
if err := json.Unmarshal(body, &result); err != nil {
return nil, err
return nil, fmt.Errorf("unable to parse json: %w", err)
}
readmeRawURL := strings.Replace(result.ReadmeURL, "blob", "raw", -1)
readmeRawURL := strings.ReplaceAll(result.ReadmeURL, "blob", "raw")
if res.StatusCode == http.StatusOK {
// nolint:bodyclose
//nolint:bodyclose
// it is closed on the caller
resp, err := http.Get(readmeRawURL) // nolint: gosec
resp, err := http.Get(readmeRawURL) //nolint: gosec,noctx
if err != nil {
return nil, err
return nil, fmt.Errorf("unable to get url: %w", err)
}
if resp.StatusCode == http.StatusOK {

11
log.go
View file

@ -1,6 +1,7 @@
package main
import (
"fmt"
"io"
"os"
"path/filepath"
@ -12,7 +13,7 @@ import (
func getLogFilePath() (string, error) {
dir, err := gap.NewScope(gap.User, "glow").CacheDir()
if err != nil {
return "", err
return "", fmt.Errorf("unable to get cache dir: %w", err)
}
return filepath.Join(dir, "glow.log"), nil
}
@ -24,14 +25,14 @@ func setupLog() (func() error, error) {
if err != nil {
return nil, err
}
if err := os.MkdirAll(filepath.Dir(logFile), 0o755); err != nil {
if err := os.MkdirAll(filepath.Dir(logFile), 0o755); err != nil { //nolint:gosec
// log disabled
return func() error { return nil }, nil
return func() error { return nil }, nil //nolint:nilerr
}
f, err := os.OpenFile(logFile, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0o644)
f, err := os.OpenFile(logFile, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0o644) //nolint:gosec
if err != nil {
// log disabled
return func() error { return nil }, nil
return func() error { return nil }, nil //nolint:nilerr
}
log.SetOutput(f)
log.SetLevel(log.DebugLevel)

55
main.go
View file

@ -1,3 +1,4 @@
// Package main provides the entry point for the Glow CLI application.
package main
import (
@ -83,15 +84,15 @@ func sourceFromArg(arg string) (*source, error) {
}
// HTTP(S) URLs:
if u, err := url.ParseRequestURI(arg); err == nil && strings.Contains(arg, "://") {
if u, err := url.ParseRequestURI(arg); err == nil && strings.Contains(arg, "://") { //nolint:nestif
if u.Scheme != "" {
if u.Scheme != "http" && u.Scheme != "https" {
return nil, fmt.Errorf("%s is not a supported protocol", u.Scheme)
}
// consumer of the source is responsible for closing the ReadCloser.
resp, err := http.Get(u.String()) // nolint:bodyclose
resp, err := http.Get(u.String()) //nolint: noctx,bodyclose
if err != nil {
return nil, err
return nil, fmt.Errorf("unable to get url: %w", err)
}
if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("HTTP status %d", resp.StatusCode)
@ -106,7 +107,7 @@ func sourceFromArg(arg string) (*source, error) {
arg = "."
}
st, err := os.Stat(arg)
if err == nil && st.IsDir() {
if err == nil && st.IsDir() { //nolint:nestif
var src *source
_ = filepath.Walk(arg, func(path string, _ os.FileInfo, err error) error {
if err != nil {
@ -136,10 +137,15 @@ func sourceFromArg(arg string) (*source, error) {
return nil, errors.New("missing markdown source")
}
// a file:
r, err := os.Open(arg)
u, _ := filepath.Abs(arg)
return &source{r, u}, err
if err != nil {
return nil, fmt.Errorf("unable to open file: %w", err)
}
u, err := filepath.Abs(arg)
if err != nil {
return nil, fmt.Errorf("unable to get absolute path: %w", err)
}
return &source{r, u}, nil
}
// validateStyle checks if the style is a default style, if not, checks that
@ -148,9 +154,9 @@ func validateStyle(style string) error {
if style != "auto" && styles.DefaultStyles[style] == nil {
style = utils.ExpandPath(style)
if _, err := os.Stat(style); errors.Is(err, fs.ErrNotExist) {
return fmt.Errorf("Specified style does not exist: %s", style)
return fmt.Errorf("specified style does not exist: %s", style)
} else if err != nil {
return err
return fmt.Errorf("unable to stat file: %w", err)
}
}
return nil
@ -166,7 +172,7 @@ func validateOptions(cmd *cobra.Command) error {
preserveNewLines = viper.GetBool("preserveNewLines")
if pager && tui {
return errors.New("glow: cannot use both pager and tui")
return errors.New("cannot use both pager and tui")
}
// validate the glamour style
@ -183,11 +189,11 @@ func validateOptions(cmd *cobra.Command) error {
}
// Detect terminal width
if !cmd.Flags().Changed("width") {
if !cmd.Flags().Changed("width") { //nolint:nestif
if isTerminal && width == 0 {
w, _, err := term.GetSize(int(os.Stdout.Fd()))
if err == nil {
width = uint(w)
width = uint(w) //nolint:gosec
}
if width > 120 {
@ -204,7 +210,7 @@ func validateOptions(cmd *cobra.Command) error {
func stdinIsPipe() (bool, error) {
stat, err := os.Stdin.Stat()
if err != nil {
return false, err
return false, fmt.Errorf("unable to open file: %w", err)
}
if stat.Mode()&os.ModeCharDevice == 0 || stat.Size() > 0 {
return true, nil
@ -266,7 +272,7 @@ func executeArg(cmd *cobra.Command, arg string, w io.Writer) error {
func executeCLI(cmd *cobra.Command, src *source, w io.Writer) error {
b, err := io.ReadAll(src.reader)
if err != nil {
return err
return fmt.Errorf("unable to read from reader: %w", err)
}
b = utils.RemoveFrontmatter(b)
@ -285,12 +291,12 @@ func executeCLI(cmd *cobra.Command, src *source, w io.Writer) error {
r, err := glamour.NewTermRenderer(
glamour.WithColorProfile(lipgloss.ColorProfile()),
utils.GlamourStyle(style, isCode),
glamour.WithWordWrap(int(width)),
glamour.WithWordWrap(int(width)), //nolint:gosec
glamour.WithBaseURL(baseURL),
glamour.WithPreservedNewLines(),
)
if err != nil {
return err
return fmt.Errorf("unable to create renderer: %w", err)
}
content := string(b)
@ -301,7 +307,7 @@ func executeCLI(cmd *cobra.Command, src *source, w io.Writer) error {
out, err := r.Render(content)
if err != nil {
return err
return fmt.Errorf("unable to render markdown: %w", err)
}
// display
@ -313,15 +319,20 @@ func executeCLI(cmd *cobra.Command, src *source, w io.Writer) error {
}
pa := strings.Split(pagerCmd, " ")
c := exec.Command(pa[0], pa[1:]...) // nolint:gosec
c := exec.Command(pa[0], pa[1:]...) //nolint:gosec
c.Stdin = strings.NewReader(out)
c.Stdout = os.Stdout
return c.Run()
if err := c.Run(); err != nil {
return fmt.Errorf("unable to run command: %w", err)
}
return nil
case tui || cmd.Flags().Changed("tui"):
return runTUI(src.URL, content)
default:
_, err = fmt.Fprint(w, out)
return err
if _, err = fmt.Fprint(w, out); err != nil {
return fmt.Errorf("unable to write to writer: %w", err)
}
return nil
}
}
@ -346,7 +357,7 @@ func runTUI(path string, content string) error {
// Run Bubble Tea program
if _, err := ui.NewProgram(cfg, content).Run(); err != nil {
return err
return fmt.Errorf("unable to run tui program: %w", err)
}
return nil

View file

@ -19,9 +19,11 @@ var manCmd = &cobra.Command{
RunE: func(*cobra.Command, []string) error {
manPage, err := mcobra.NewManPage(1, rootCmd)
if err != nil {
return err
return fmt.Errorf("unable to instantiate man page: %w", err)
}
_, err = fmt.Fprint(os.Stdout, manPage.Build(roff.NewDocument()))
return err
if _, err := fmt.Fprint(os.Stdout, manPage.Build(roff.NewDocument())); err != nil {
return fmt.Errorf("unable to build man page: %w", err)
}
return nil
},
}

View file

@ -11,7 +11,7 @@ func openEditor(path string, lineno int) tea.Cmd {
cb := func(err error) tea.Msg {
return editorFinishedMsg{err}
}
cmd, err := editor.Cmd("Glow", path, editor.OpenAtLine(uint(lineno)))
cmd, err := editor.Cmd("Glow", path, editor.LineNumber(uint(lineno))) //nolint:gosec
if err != nil {
return func() tea.Msg { return cb(err) }
}

View file

@ -1,6 +1,7 @@
package ui
import (
"fmt"
"math"
"time"
"unicode"
@ -48,7 +49,10 @@ func (m markdown) relativeTime() string {
func normalize(in string) (string, error) {
t := transform.Chain(norm.NFD, runes.Remove(runes.In(unicode.Mn)), norm.NFC)
out, _, err := transform.String(t, in)
return out, err
if err != nil {
return "", fmt.Errorf("error normalizing: %w", err)
}
return out, nil
}
// Return the time in a human-readable format relative to the current time.

View file

@ -317,7 +317,7 @@ func (m pagerModel) statusBarView(b *strings.Builder) {
} else {
note = m.currentDocument.Note
}
note = truncate.StringWithTail(" "+note+" ", uint(max(0,
note = truncate.StringWithTail(" "+note+" ", uint(max(0, //nolint:gosec
m.common.width-
ansi.PrintableRuneWidth(logo)-
ansi.PrintableRuneWidth(scrollPercent)-
@ -415,7 +415,7 @@ func glamourRender(m pagerModel, markdown string) (string, error) {
}
isCode := !utils.IsMarkdownFile(m.currentDocument.Note)
width := max(0, min(int(m.common.cfg.GlamourMaxWidth), m.viewport.Width))
width := max(0, min(int(m.common.cfg.GlamourMaxWidth), m.viewport.Width)) //nolint:gosec
if isCode {
width = 0
}
@ -430,7 +430,7 @@ func glamourRender(m pagerModel, markdown string) (string, error) {
}
r, err := glamour.NewTermRenderer(options...)
if err != nil {
return "", err
return "", fmt.Errorf("error creating glamour renderer: %w", err)
}
if isCode {
@ -439,7 +439,7 @@ func glamourRender(m pagerModel, markdown string) (string, error) {
out, err := r.Render(markdown)
if err != nil {
return "", err
return "", fmt.Errorf("error rendering markdown: %w", err)
}
if isCode {

View file

@ -126,7 +126,7 @@ func initSections() {
// String returns a styled version of the status message appropriate for the
// given context.
func (s statusMessage) String() string {
switch s.status {
switch s.status { //nolint:exhaustive
case subtleStatusMessage:
return dimGreenFg(s.message)
case errorStatusMessage:
@ -444,7 +444,7 @@ func (m stashModel) update(msg tea.Msg) (stashModel, tea.Cmd) {
}
// Updates per the current state
switch m.viewState {
switch m.viewState { //nolint:exhaustive
case stashStateReady:
cmds = append(cmds, m.handleDocumentBrowsing(msg))
case stashStateShowingError:
@ -596,7 +596,7 @@ func (m *stashModel) handleFiltering(msg tea.Msg) tea.Cmd {
var cmds []tea.Cmd
// Handle keys
if msg, ok := msg.(tea.KeyMsg); ok {
if msg, ok := msg.(tea.KeyMsg); ok { //nolint:nestif
switch msg.String() {
case keyEsc:
// Cancel filtering
@ -690,7 +690,7 @@ func (m stashModel) view() string {
logoOrFilter += " " + m.statusMessage.String()
}
}
logoOrFilter = truncate.StringWithTail(logoOrFilter, uint(m.common.width-1), ellipsis)
logoOrFilter = truncate.StringWithTail(logoOrFilter, uint(m.common.width-1), ellipsis) //nolint:gosec
help, helpHeight := m.helpView()

View file

@ -17,7 +17,7 @@ const (
func stashItemView(b *strings.Builder, m stashModel, index int, md *markdown) {
var (
truncateTo = uint(m.common.width - stashViewHorizontalPadding*2)
truncateTo = uint(m.common.width - stashViewHorizontalPadding*2) //nolint:gosec
gutter string
title = truncate.StringWithTail(md.Note, truncateTo, ellipsis)
date = md.relativeTime()
@ -34,7 +34,7 @@ func stashItemView(b *strings.Builder, m stashModel, index int, md *markdown) {
// If there are multiple items being filtered don't highlight a selected
// item in the results. If we've filtered down to one item, however,
// highlight that first item since pressing return will open it.
if isSelected && !isFiltering || singleFilteredItem {
if isSelected && !isFiltering || singleFilteredItem { //nolint:nestif
// Selected item
if m.statusMessage == stashingStatusMessage {
gutter = greenFg(verticalLine)

View file

@ -1,3 +1,4 @@
// Package ui provides the main UI for the glow application.
package ui
import (
@ -120,7 +121,7 @@ func (m *model) unloadDocument() []tea.Cmd {
var batch []tea.Cmd
if m.pager.viewport.HighPerformanceRendering {
batch = append(batch, tea.ClearScrollArea)
batch = append(batch, tea.ClearScrollArea) //nolint:staticcheck
}
if !m.stash.shouldSpin() {
@ -234,7 +235,7 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
case "q":
var cmd tea.Cmd
switch m.state {
switch m.state { //nolint:exhaustive
case stateShowStash:
// pass through all keys if we're editing the filter
if m.stash.filterState == filtering {
@ -328,7 +329,7 @@ func (m model) View() string {
return errorView(m.fatalErr, true)
}
switch m.state {
switch m.state { //nolint:exhaustive
case stateShowDocument:
return m.pager.View()
default:
@ -449,17 +450,3 @@ func indent(s string, n int) string {
}
return b.String()
}
func min(a, b int) int {
if a < b {
return a
}
return b
}
func max(a, b int) int {
if a > b {
return a
}
return b
}

3
url.go
View file

@ -1,6 +1,7 @@
package main
import (
"fmt"
"net/url"
"strings"
"sync"
@ -44,7 +45,7 @@ func readmeURL(path string) (*source, error) {
}
u, err := url.Parse(path)
if err != nil {
return nil, err
return nil, fmt.Errorf("unable to parse url: %w", err)
}
switch {

View file

@ -1,3 +1,4 @@
// Package utils provides utility functions.
package utils
import (
@ -30,7 +31,7 @@ func detectFrontmatter(c []byte) []int {
return []int{-1, -1}
}
// Expands tilde and all environment variables from the given path.
// ExpandPath expands tilde and all environment variables from the given path.
func ExpandPath(path string) string {
s, err := homedir.Expand(path)
if err == nil {
@ -68,13 +69,13 @@ func IsMarkdownFile(filename string) bool {
return false
}
// GlamourStyle returns a glamour.TermRendererOption based on the given style.
func GlamourStyle(style string, isCode bool) glamour.TermRendererOption {
if !isCode {
if style == styles.AutoStyle {
return glamour.WithAutoStyle()
} else {
return glamour.WithStylePath(style)
}
return glamour.WithStylePath(style)
}
// If we are rendering a pure code block, we need to modify the style to