mirror of
https://github.com/kovidgoyal/kitty
synced 2026-06-08 14:18:26 +02:00
Move error handling code into its own library
This commit is contained in:
1
go.mod
1
go.mod
@@ -13,6 +13,7 @@ require (
|
|||||||
github.com/google/uuid v1.6.0
|
github.com/google/uuid v1.6.0
|
||||||
github.com/kovidgoyal/dbus v0.0.0-20250519011319-e811c41c0bc1
|
github.com/kovidgoyal/dbus v0.0.0-20250519011319-e811c41c0bc1
|
||||||
github.com/kovidgoyal/exiffix v0.0.0-20250919160812-dbef770c2032
|
github.com/kovidgoyal/exiffix v0.0.0-20250919160812-dbef770c2032
|
||||||
|
github.com/kovidgoyal/go-parallel v1.0.1
|
||||||
github.com/kovidgoyal/imaging v1.7.1
|
github.com/kovidgoyal/imaging v1.7.1
|
||||||
github.com/seancfoley/ipaddress-go v1.7.1
|
github.com/seancfoley/ipaddress-go v1.7.1
|
||||||
github.com/shirou/gopsutil/v3 v3.24.5
|
github.com/shirou/gopsutil/v3 v3.24.5
|
||||||
|
|||||||
2
go.sum
2
go.sum
@@ -28,6 +28,8 @@ github.com/kovidgoyal/dbus v0.0.0-20250519011319-e811c41c0bc1 h1:rMY/hWfcVzBm6BL
|
|||||||
github.com/kovidgoyal/dbus v0.0.0-20250519011319-e811c41c0bc1/go.mod h1:RbNG3Q1g6GUy1/WzWVx+S24m7VKyvl57vV+cr2hpt50=
|
github.com/kovidgoyal/dbus v0.0.0-20250519011319-e811c41c0bc1/go.mod h1:RbNG3Q1g6GUy1/WzWVx+S24m7VKyvl57vV+cr2hpt50=
|
||||||
github.com/kovidgoyal/exiffix v0.0.0-20250919160812-dbef770c2032 h1:TEV9lpo2a6fP1byiDsoJe2fXpvrj2itae41xMM+bEAg=
|
github.com/kovidgoyal/exiffix v0.0.0-20250919160812-dbef770c2032 h1:TEV9lpo2a6fP1byiDsoJe2fXpvrj2itae41xMM+bEAg=
|
||||||
github.com/kovidgoyal/exiffix v0.0.0-20250919160812-dbef770c2032/go.mod h1:VU38Nlbvb0lbyS5YkopCZMS5HuJ5QLVJBxRWyzq79q4=
|
github.com/kovidgoyal/exiffix v0.0.0-20250919160812-dbef770c2032/go.mod h1:VU38Nlbvb0lbyS5YkopCZMS5HuJ5QLVJBxRWyzq79q4=
|
||||||
|
github.com/kovidgoyal/go-parallel v1.0.1 h1:nYUjN+EdpbmQjTg3N5eTUInuXTB3/1oD2vHdaMfuHoI=
|
||||||
|
github.com/kovidgoyal/go-parallel v1.0.1/go.mod h1:BJNIbe6+hxyFWv7n6oEDPj3PA5qSw5OCtf0hcVxWJiw=
|
||||||
github.com/kovidgoyal/imaging v1.7.1 h1:wQJf0LdE06kIlSFIFFBKJp9N4D0CJmNMfWuog+YQka4=
|
github.com/kovidgoyal/imaging v1.7.1 h1:wQJf0LdE06kIlSFIFFBKJp9N4D0CJmNMfWuog+YQka4=
|
||||||
github.com/kovidgoyal/imaging v1.7.1/go.mod h1:i0dBmu7j5/g4QhvS79Cx9IoiK7P02z1SwBJFDazrGLE=
|
github.com/kovidgoyal/imaging v1.7.1/go.mod h1:i0dBmu7j5/g4QhvS79Cx9IoiK7P02z1SwBJFDazrGLE=
|
||||||
github.com/lufia/plan9stats v0.0.0-20230326075908-cb1d2100619a h1:N9zuLhTvBSRt0gWSiJswwQ2HqDmtX/ZCDJURnKUt1Ik=
|
github.com/lufia/plan9stats v0.0.0-20230326075908-cb1d2100619a h1:N9zuLhTvBSRt0gWSiJswwQ2HqDmtX/ZCDJURnKUt1Ik=
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
|
|
||||||
|
"github.com/kovidgoyal/go-parallel"
|
||||||
"github.com/kovidgoyal/kitty/tools/disk_cache"
|
"github.com/kovidgoyal/kitty/tools/disk_cache"
|
||||||
"github.com/kovidgoyal/kitty/tools/icons"
|
"github.com/kovidgoyal/kitty/tools/icons"
|
||||||
"github.com/kovidgoyal/kitty/tools/utils"
|
"github.com/kovidgoyal/kitty/tools/utils"
|
||||||
@@ -114,8 +115,7 @@ func (p *ImagePreview) ensure_source_image() (err error) {
|
|||||||
func (p *ImagePreview) render_image(h *Handler, x, y, width, height int) {
|
func (p *ImagePreview) render_image(h *Handler, x, y, width, height int) {
|
||||||
defer func() {
|
defer func() {
|
||||||
if r := recover(); r != nil {
|
if r := recover(); r != nil {
|
||||||
text, _ := utils.Format_stacktrace_on_panic(r)
|
h.err_chan <- parallel.Format_stacktrace_on_panic(r, 1)
|
||||||
h.err_chan <- fmt.Errorf("%s", text)
|
|
||||||
p.WakeupMainThread()
|
p.WakeupMainThread()
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
@@ -160,8 +160,7 @@ func (p *ImagePreview) Render(h *Handler, x, y, width, height int) {
|
|||||||
func (p *ImagePreview) start_rendering() {
|
func (p *ImagePreview) start_rendering() {
|
||||||
defer func() {
|
defer func() {
|
||||||
if r := recover(); r != nil {
|
if r := recover(); r != nil {
|
||||||
text, _ := utils.Format_stacktrace_on_panic(r)
|
p.render_channel <- render_data{err: parallel.Format_stacktrace_on_panic(r, 1)}
|
||||||
p.render_channel <- render_data{err: fmt.Errorf("%s", text)}
|
|
||||||
}
|
}
|
||||||
close(p.render_channel)
|
close(p.render_channel)
|
||||||
p.WakeupMainThread()
|
p.WakeupMainThread()
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
"unicode/utf8"
|
"unicode/utf8"
|
||||||
|
|
||||||
|
"github.com/kovidgoyal/go-parallel"
|
||||||
"github.com/kovidgoyal/kitty/tools/highlight"
|
"github.com/kovidgoyal/kitty/tools/highlight"
|
||||||
"github.com/kovidgoyal/kitty/tools/icons"
|
"github.com/kovidgoyal/kitty/tools/icons"
|
||||||
"github.com/kovidgoyal/kitty/tools/tui/loop"
|
"github.com/kovidgoyal/kitty/tools/tui/loop"
|
||||||
@@ -261,8 +262,8 @@ func (pm *PreviewManager) highlight_file_async(path string, output chan highligh
|
|||||||
go func() {
|
go func() {
|
||||||
defer func() {
|
defer func() {
|
||||||
if r := recover(); r != nil {
|
if r := recover(); r != nil {
|
||||||
text, _ := utils.Format_stacktrace_on_panic(r)
|
err := parallel.Format_stacktrace_on_panic(r, 1)
|
||||||
debugprintln(fmt.Sprintf("Failed to highlight: %s with panic: %s", path, text))
|
debugprintln(fmt.Sprintf("Failed to highlight: %s with panic: %s", path, err))
|
||||||
}
|
}
|
||||||
close(output)
|
close(output)
|
||||||
pm.WakeupMainThread()
|
pm.WakeupMainThread()
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import (
|
|||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/kovidgoyal/go-parallel"
|
||||||
"github.com/kovidgoyal/kitty/tools/cli"
|
"github.com/kovidgoyal/kitty/tools/cli"
|
||||||
"github.com/kovidgoyal/kitty/tools/tui/loop"
|
"github.com/kovidgoyal/kitty/tools/tui/loop"
|
||||||
"github.com/kovidgoyal/kitty/tools/utils"
|
"github.com/kovidgoyal/kitty/tools/utils"
|
||||||
@@ -26,8 +27,7 @@ func FilePromptCompleter(getcwd func() string) func(string, string) *cli.Complet
|
|||||||
return func(before_cursor, after_cursor string) (ans *cli.Completions) {
|
return func(before_cursor, after_cursor string) (ans *cli.Completions) {
|
||||||
defer func() {
|
defer func() {
|
||||||
if r := recover(); r != nil {
|
if r := recover(); r != nil {
|
||||||
text, err := utils.Format_stacktrace_on_panic(r)
|
err := parallel.Format_stacktrace_on_panic(r, 1)
|
||||||
debugprintln(text)
|
|
||||||
debugprintln(err)
|
debugprintln(err)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ import (
|
|||||||
"unicode"
|
"unicode"
|
||||||
"unicode/utf8"
|
"unicode/utf8"
|
||||||
|
|
||||||
|
"github.com/kovidgoyal/go-parallel"
|
||||||
"github.com/kovidgoyal/kitty/tools/fzf"
|
"github.com/kovidgoyal/kitty/tools/fzf"
|
||||||
"github.com/kovidgoyal/kitty/tools/ignorefiles"
|
"github.com/kovidgoyal/kitty/tools/ignorefiles"
|
||||||
"github.com/kovidgoyal/kitty/tools/utils"
|
"github.com/kovidgoyal/kitty/tools/utils"
|
||||||
@@ -219,8 +220,8 @@ func (fss *FileSystemScanner) worker() {
|
|||||||
defer fss.unlock()
|
defer fss.unlock()
|
||||||
fss.in_progress.Store(false)
|
fss.in_progress.Store(false)
|
||||||
if r := recover(); r != nil {
|
if r := recover(); r != nil {
|
||||||
st, qerr := utils.Format_stacktrace_on_panic(r)
|
qerr := parallel.Format_stacktrace_on_panic(r, 1)
|
||||||
fss.err = fmt.Errorf("%w\n%s", qerr, st)
|
fss.err = qerr
|
||||||
}
|
}
|
||||||
for _, l := range fss.listeners {
|
for _, l := range fss.listeners {
|
||||||
close(l)
|
close(l)
|
||||||
@@ -532,8 +533,8 @@ func (fss *FileSystemScorer) worker(on_results chan bool, worker_wait *sync.Wait
|
|||||||
defer worker_wait.Done()
|
defer worker_wait.Done()
|
||||||
if r := recover(); r != nil {
|
if r := recover(); r != nil {
|
||||||
if fss.keep_going.Load() {
|
if fss.keep_going.Load() {
|
||||||
st, qerr := utils.Format_stacktrace_on_panic(r)
|
qerr := parallel.Format_stacktrace_on_panic(r, 1)
|
||||||
fss.on_results(fmt.Errorf("%w\n%s", qerr, st), true)
|
fss.on_results(qerr, true)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if fss.keep_going.Load() {
|
if fss.keep_going.Load() {
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import (
|
|||||||
"unicode"
|
"unicode"
|
||||||
"unicode/utf8"
|
"unicode/utf8"
|
||||||
|
|
||||||
"github.com/kovidgoyal/kitty/tools/utils"
|
"github.com/kovidgoyal/go-parallel"
|
||||||
"golang.org/x/text/unicode/norm"
|
"golang.org/x/text/unicode/norm"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -362,12 +362,11 @@ func (m *FuzzyMatcher) score(items []string, pattern string, scoring_func func(s
|
|||||||
pat := []rune(pattern)
|
pat := []rune(pattern)
|
||||||
pattern_is_ascii := !slices.ContainsFunc(pat, func(r rune) bool { return r >= utf8.RuneSelf })
|
pattern_is_ascii := !slices.ContainsFunc(pat, func(r rune) bool { return r >= utf8.RuneSelf })
|
||||||
ans = make([]Result, len(items))
|
ans = make([]Result, len(items))
|
||||||
err = utils.Run_in_parallel_over_range(0, func(start, end int) error {
|
err = parallel.Run_in_parallel_over_range(0, func(start, end int) {
|
||||||
s := slab{}
|
s := slab{}
|
||||||
for i := start; i < end; i++ {
|
for i := start; i < end; i++ {
|
||||||
ans[i] = scoring_func(items[i], pat, pattern_is_ascii, &s, as_chars)
|
ans[i] = scoring_func(items[i], pat, pattern_is_ascii, &s, as_chars)
|
||||||
}
|
}
|
||||||
return nil
|
|
||||||
}, 0, len(items))
|
}, 0, len(items))
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import (
|
|||||||
"github.com/alecthomas/chroma/v2"
|
"github.com/alecthomas/chroma/v2"
|
||||||
"github.com/alecthomas/chroma/v2/lexers"
|
"github.com/alecthomas/chroma/v2/lexers"
|
||||||
"github.com/alecthomas/chroma/v2/styles"
|
"github.com/alecthomas/chroma/v2/styles"
|
||||||
|
"github.com/kovidgoyal/go-parallel"
|
||||||
"github.com/kovidgoyal/kitty/tools/utils"
|
"github.com/kovidgoyal/kitty/tools/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -185,8 +186,7 @@ func (h *highlighter) Sanitize(x string) string { return h.sanitize(x) }
|
|||||||
func (h *highlighter) HighlightFile(path string, srd StyleResolveData) (highlighted_string string, err error) {
|
func (h *highlighter) HighlightFile(path string, srd StyleResolveData) (highlighted_string string, err error) {
|
||||||
defer func() {
|
defer func() {
|
||||||
if r := recover(); r != nil {
|
if r := recover(); r != nil {
|
||||||
text, _ := utils.Format_stacktrace_on_panic(r)
|
err = parallel.Format_stacktrace_on_panic(r, 1)
|
||||||
err = fmt.Errorf("%s", text)
|
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
filename_for_detection := filepath.Base(path)
|
filename_for_detection := filepath.Base(path)
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import (
|
|||||||
|
|
||||||
"golang.org/x/sys/unix"
|
"golang.org/x/sys/unix"
|
||||||
|
|
||||||
|
"github.com/kovidgoyal/go-parallel"
|
||||||
"github.com/kovidgoyal/kitty/tools/tty"
|
"github.com/kovidgoyal/kitty/tools/tty"
|
||||||
"github.com/kovidgoyal/kitty/tools/utils"
|
"github.com/kovidgoyal/kitty/tools/utils"
|
||||||
"github.com/kovidgoyal/kitty/tools/utils/style"
|
"github.com/kovidgoyal/kitty/tools/utils/style"
|
||||||
@@ -324,18 +325,17 @@ func (self *Loop) DebugPrintln(args ...any) {
|
|||||||
func (self *Loop) Run() (err error) {
|
func (self *Loop) Run() (err error) {
|
||||||
defer func() {
|
defer func() {
|
||||||
if r := recover(); r != nil {
|
if r := recover(); r != nil {
|
||||||
var text string
|
err = parallel.Format_stacktrace_on_panic(r, 1)
|
||||||
text, err = utils.Format_stacktrace_on_panic(r)
|
|
||||||
is_terminal := tty.IsTerminal(os.Stderr.Fd())
|
is_terminal := tty.IsTerminal(os.Stderr.Fd())
|
||||||
if is_terminal {
|
if is_terminal {
|
||||||
os.Stderr.WriteString("\x1b]\x1b\\\x1bc\x1b[H\x1b[2J") // reset terminal
|
os.Stderr.WriteString("\x1b]\x1b\\\x1bc\x1b[H\x1b[2J") // reset terminal
|
||||||
}
|
}
|
||||||
os.Stderr.WriteString(text)
|
os.Stderr.WriteString(err.Error())
|
||||||
os.Stderr.WriteString("\n")
|
os.Stderr.WriteString("\n")
|
||||||
if is_terminal {
|
if is_terminal {
|
||||||
if term, err := tty.OpenControllingTerm(tty.SetRaw); err == nil {
|
if term, err := tty.OpenControllingTerm(tty.SetRaw); err == nil {
|
||||||
defer term.RestoreAndClose()
|
defer term.RestoreAndClose()
|
||||||
term.DebugPrintln(text)
|
term.DebugPrintln(err.Error())
|
||||||
fmt.Println("Press any key to exit.\r")
|
fmt.Println("Press any key to exit.\r")
|
||||||
buf := make([]byte, 16)
|
buf := make([]byte, 16)
|
||||||
_, _ = term.Read(buf)
|
_, _ = term.Read(buf)
|
||||||
@@ -592,8 +592,7 @@ type SizedText struct {
|
|||||||
|
|
||||||
func (self *Loop) RecoverFromPanicInGoRoutine() {
|
func (self *Loop) RecoverFromPanicInGoRoutine() {
|
||||||
if r := recover(); r != nil {
|
if r := recover(); r != nil {
|
||||||
text, err := utils.Format_stacktrace_on_panic(r)
|
err := parallel.Format_stacktrace_on_panic(r, 1)
|
||||||
err = fmt.Errorf("Panicked in non-main go routine\n%s\n%w", text, err)
|
|
||||||
// print to kitty stdout as multiple go routines might panic but only
|
// print to kitty stdout as multiple go routines might panic but only
|
||||||
// one panic is reported by the main loop panic_channel
|
// one panic is reported by the main loop panic_channel
|
||||||
if f := tty.KittyStdout(); f != nil {
|
if f := tty.KittyStdout(); f != nil {
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import (
|
|||||||
|
|
||||||
"golang.org/x/sys/unix"
|
"golang.org/x/sys/unix"
|
||||||
|
|
||||||
|
"github.com/kovidgoyal/go-parallel"
|
||||||
"github.com/kovidgoyal/kitty/tools/tty"
|
"github.com/kovidgoyal/kitty/tools/tty"
|
||||||
"github.com/kovidgoyal/kitty/tools/utils"
|
"github.com/kovidgoyal/kitty/tools/utils"
|
||||||
)
|
)
|
||||||
@@ -46,8 +47,8 @@ func read_ignoring_temporary_errors(f *tty.Term, buf []byte) (int, error) {
|
|||||||
func read_from_tty(pipe_r *os.File, term *tty.Term, results_channel chan<- []byte, err_channel chan<- error, quit_channel <-chan byte, leftover_channel chan<- []byte) {
|
func read_from_tty(pipe_r *os.File, term *tty.Term, results_channel chan<- []byte, err_channel chan<- error, quit_channel <-chan byte, leftover_channel chan<- []byte) {
|
||||||
defer func() {
|
defer func() {
|
||||||
if r := recover(); r != nil {
|
if r := recover(); r != nil {
|
||||||
text, _ := utils.Format_stacktrace_on_panic(r)
|
err := parallel.Format_stacktrace_on_panic(r, 1)
|
||||||
err_channel <- fmt.Errorf("%s", text)
|
err_channel <- err
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
keep_going := true
|
keep_going := true
|
||||||
@@ -123,7 +124,7 @@ func read_until_primary_device_attributes_response(term *tty.Term, initial_bytes
|
|||||||
go func() {
|
go func() {
|
||||||
defer func() {
|
defer func() {
|
||||||
if r := recover(); r != nil {
|
if r := recover(); r != nil {
|
||||||
text, _ := utils.Format_stacktrace_on_panic(r)
|
text := parallel.Format_stacktrace_on_panic(r, 1).Error()
|
||||||
received <- fmt.Errorf("%s", text)
|
received <- fmt.Errorf("%s", text)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import (
|
|||||||
|
|
||||||
"golang.org/x/sys/unix"
|
"golang.org/x/sys/unix"
|
||||||
|
|
||||||
|
"github.com/kovidgoyal/go-parallel"
|
||||||
"github.com/kovidgoyal/kitty/tools/tty"
|
"github.com/kovidgoyal/kitty/tools/tty"
|
||||||
"github.com/kovidgoyal/kitty/tools/utils"
|
"github.com/kovidgoyal/kitty/tools/utils"
|
||||||
)
|
)
|
||||||
@@ -170,8 +171,7 @@ func write_to_tty(
|
|||||||
) {
|
) {
|
||||||
defer func() {
|
defer func() {
|
||||||
if r := recover(); r != nil {
|
if r := recover(); r != nil {
|
||||||
text, _ := utils.Format_stacktrace_on_panic(r)
|
err_channel <- parallel.Format_stacktrace_on_panic(r, 1)
|
||||||
err_channel <- fmt.Errorf("%s", text)
|
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
keep_going := true
|
keep_going := true
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import (
|
|||||||
"slices"
|
"slices"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/kovidgoyal/go-parallel"
|
||||||
"github.com/kovidgoyal/kitty/tools/utils"
|
"github.com/kovidgoyal/kitty/tools/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -215,12 +216,11 @@ func ScoreItems(query string, items []string, opts Options) []*Match {
|
|||||||
ropts := resolved_options_type{
|
ropts := resolved_options_type{
|
||||||
level1: []rune(opts.Level1), level2: []rune(opts.Level2), level3: []rune(opts.Level3),
|
level1: []rune(opts.Level1), level2: []rune(opts.Level2), level3: []rune(opts.Level3),
|
||||||
}
|
}
|
||||||
utils.Run_in_parallel_over_range(opts.NumberOfThreads, func(start, limit int) error {
|
parallel.Run_in_parallel_over_range(opts.NumberOfThreads, func(start, limit int) {
|
||||||
w := workspace_type{}
|
w := workspace_type{}
|
||||||
for i := start; i < limit; i++ {
|
for i := start; i < limit; i++ {
|
||||||
ans[i] = score_item(items[i], i, nr, &ropts, &w)
|
ans[i] = score_item(items[i], i, nr, &ropts, &w)
|
||||||
}
|
}
|
||||||
return nil
|
|
||||||
}, 0, len(items))
|
}, 0, len(items))
|
||||||
return ans
|
return ans
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
|
|
||||||
"github.com/kovidgoyal/kitty/tools/utils"
|
"github.com/kovidgoyal/go-parallel"
|
||||||
)
|
)
|
||||||
|
|
||||||
var _ = fmt.Print
|
var _ = fmt.Print
|
||||||
@@ -55,8 +55,7 @@ func (self *Context) SafeParallel(start, stop int, fn func(<-chan int)) (err err
|
|||||||
go func() {
|
go func() {
|
||||||
defer func() {
|
defer func() {
|
||||||
if r := recover(); r != nil {
|
if r := recover(); r != nil {
|
||||||
text, _ := utils.Format_stacktrace_on_panic(r)
|
err = parallel.Format_stacktrace_on_panic(r, 1)
|
||||||
err = fmt.Errorf("%s", text)
|
|
||||||
}
|
}
|
||||||
wg.Done()
|
wg.Done()
|
||||||
}()
|
}()
|
||||||
|
|||||||
@@ -68,80 +68,6 @@ func Filter[T any](s []T, f func(x T) bool) []T {
|
|||||||
return ans
|
return ans
|
||||||
}
|
}
|
||||||
|
|
||||||
func Format_stacktrace_on_panic(r any) (text string, err error) {
|
|
||||||
pcs := make([]uintptr, 512)
|
|
||||||
n := runtime.Callers(3, pcs)
|
|
||||||
lines := []string{}
|
|
||||||
frames := runtime.CallersFrames(pcs[:n])
|
|
||||||
rt := fmt.Sprint(r)
|
|
||||||
if strings.HasPrefix(rt, "Panicked with error:") {
|
|
||||||
err = fmt.Errorf("%s", rt)
|
|
||||||
lines = append(lines, "Panic caused by previous panic (probably in a gouroutine). Previous panic:\r\n")
|
|
||||||
lines = append(lines, rt)
|
|
||||||
lines = append(lines, "\r\n\r\nStacktrace of current panic (most recent call first):\r\n")
|
|
||||||
} else {
|
|
||||||
err = fmt.Errorf("Panicked: %s", r)
|
|
||||||
lines = append(lines, fmt.Sprintf("\r\nPanicked with error: %s\r\nStacktrace (most recent call first):\r\n", r))
|
|
||||||
}
|
|
||||||
found_first_frame := false
|
|
||||||
for frame, more := frames.Next(); more; frame, more = frames.Next() {
|
|
||||||
if !found_first_frame {
|
|
||||||
if strings.HasPrefix(frame.Function, "runtime.") {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
found_first_frame = true
|
|
||||||
}
|
|
||||||
lines = append(lines, fmt.Sprintf("%s\r\n\t%s:%d\r\n", frame.Function, frame.File, frame.Line))
|
|
||||||
}
|
|
||||||
text = strings.Join(lines, "")
|
|
||||||
return strings.TrimSpace(text), err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Run the specified function in parallel over chunks from the specified range.
|
|
||||||
// If the function panics, it is turned into a regular error.
|
|
||||||
func Run_in_parallel_over_range(num_procs int, f func(int, int) error, start, limit int) (err error) {
|
|
||||||
num_items := limit - start
|
|
||||||
if num_procs <= 0 {
|
|
||||||
num_procs = runtime.NumCPU()
|
|
||||||
}
|
|
||||||
num_procs = max(1, min(num_procs, num_items))
|
|
||||||
if num_procs < 2 {
|
|
||||||
defer func() {
|
|
||||||
if r := recover(); r != nil {
|
|
||||||
stacktrace, e := Format_stacktrace_on_panic(r)
|
|
||||||
err = fmt.Errorf("%s\n\n%w", stacktrace, e)
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
return f(start, limit)
|
|
||||||
}
|
|
||||||
chunk_sz := max(1, num_items/num_procs)
|
|
||||||
var wg sync.WaitGroup
|
|
||||||
echan := make(chan error, num_procs)
|
|
||||||
for start < limit {
|
|
||||||
end := min(start+chunk_sz, limit)
|
|
||||||
wg.Add(1)
|
|
||||||
go func(start, end int) {
|
|
||||||
defer func() {
|
|
||||||
if r := recover(); r != nil {
|
|
||||||
stacktrace, e := Format_stacktrace_on_panic(r)
|
|
||||||
echan <- fmt.Errorf("%s\n\n%w", stacktrace, e)
|
|
||||||
}
|
|
||||||
wg.Done()
|
|
||||||
}()
|
|
||||||
if err := f(start, end); err != nil {
|
|
||||||
echan <- err
|
|
||||||
}
|
|
||||||
}(start, end)
|
|
||||||
start = end
|
|
||||||
}
|
|
||||||
wg.Wait()
|
|
||||||
close(echan)
|
|
||||||
for qerr := range echan {
|
|
||||||
return qerr
|
|
||||||
}
|
|
||||||
return
|
|
||||||
|
|
||||||
}
|
|
||||||
func Map[T any, O any](f func(x T) O, s []T) []O {
|
func Map[T any, O any](f func(x T) O, s []T) []O {
|
||||||
ans := make([]O, 0, len(s))
|
ans := make([]O, 0, len(s))
|
||||||
for _, x := range s {
|
for _, x := range s {
|
||||||
|
|||||||
Reference in New Issue
Block a user