v0.20.1 d9a391f

normalize.go RawHistoryFolder

1// Package url provides URL manipulation utilities for the browser.
2package url
3
4import (
5	"fmt"
6	"net/url"
7	"strings"
8)
9
10// Normalize adds https:// prefix if missing for URL-like inputs.
11// Returns the input unchanged if it already has a scheme or doesn't look like a URL.
12func Normalize(input string) string {
13	if input == "" {
14		return ""
15	}
16
17	// Already has scheme
18	switch {
19	case strings.HasPrefix(input, "http://"):
20		return input
21	case strings.HasPrefix(input, "https://"):
22		return input
23	case strings.HasPrefix(input, "dumb://"):
24		return input
25	case strings.HasPrefix(input, "file://"):
26		return input
27	case strings.HasPrefix(input, "about:"):
28		return input
29	}
30
31	// Looks like a URL (contains . and no spaces)
32	if strings.Contains(input, ".") && !strings.Contains(input, " ") {
33		return "https://" + input
34	}
35
36	return input
37}
38
39// LooksLikeURL checks if the input appears to be a URL (not a search query).
40// Returns true for strings like "github.com", "google.com/search", etc.
41// Also returns true for URLs with explicit schemes like "dumb://".
42func LooksLikeURL(input string) bool {
43	if input == "" {
44		return false
45	}
46
47	// Explicit schemes should always be treated as URLs.
48	switch {
49	case strings.HasPrefix(input, "http://"):
50		return true
51	case strings.HasPrefix(input, "https://"):
52		return true
53	case strings.HasPrefix(input, "dumb://"):
54		return true
55	case strings.HasPrefix(input, "file://"):
56		return true
57	case strings.HasPrefix(input, "about:"):
58		return true
59	}
60
61	// Contains a dot and no spaces = likely a URL
62	return strings.Contains(input, ".") && !strings.Contains(input, " ")
63}
64
65// ExtractDomain extracts the normalized domain (host) from a URL string.
66// Normalizes by stripping "www." prefix so youtube.com and www.youtube.com
67// resolve to the same value.
68func ExtractDomain(rawURL string) string {
69	if rawURL == "" {
70		return ""
71	}
72	parsed, err := url.Parse(rawURL)
73	if err != nil || parsed.Host == "" {
74		return ""
75	}
76	return strings.TrimPrefix(parsed.Host, "www.")
77}
78
79// SanitizeDomainForFilename converts a domain to a safe filename with .ico extension.
80// Replaces unsafe filesystem characters with underscores.
81func SanitizeDomainForFilename(domain string) string {
82	return sanitizeDomain(domain) + ".ico"
83}
84
85// SanitizeDomainForPNG converts a domain to a safe filename with .png extension.
86// Used for favicon export for tools like rofi/fuzzel that require PNG format.
87func SanitizeDomainForPNG(domain string) string {
88	return sanitizeDomain(domain) + ".png"
89}
90
91// sanitizeDomain replaces unsafe filesystem characters with underscores.
92func sanitizeDomain(domain string) string {
93	replacer := strings.NewReplacer(
94		":", "_",
95		"/", "_",
96		"\\", "_",
97		"*", "_",
98		"?", "_",
99		"\"", "_",
100		"<", "_",
101		">", "_",
102		"|", "_",
103	)
104	return replacer.Replace(domain)
105}
106
107// SanitizeDomainForPNGSized converts a domain to a safe filename with size suffix.
108// Example: "google.com" with size 32 -> "google.com.32.png"
109// Used for normalized favicon export for tools like rofi/fuzzel.
110func SanitizeDomainForPNGSized(domain string, size int) string {
111	return fmt.Sprintf("%s.%d.png", sanitizeDomain(domain), size)
112}

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 8

Tags 42

↑↓ moveenter openesc close