Copy disabled (too large)
Download .txt
Showing preview only (20,772K chars total). Download the full file to get everything.
Repository: Wraient/curd
Branch: main
Commit: 6a0c2b9a2667
Files: 898
Total size: 19.6 MB
Directory structure:
gitextract_bu9ojwvr/
├── .gitattributes
├── .github/
│ ├── ISSUE_TEMPLATE/
│ │ └── bug_report.md
│ └── workflows/
│ ├── ci-cd.yml
│ └── update-aur.yml
├── Build/
│ ├── buildlinux
│ ├── buildlinux-arm64
│ ├── buildlinux-x86_64
│ ├── buildmac
│ ├── buildmac-arm64
│ ├── buildmac-x86_64
│ ├── buildwindows
│ ├── buildwindows-arm64
│ ├── buildwindows-x86_64
│ ├── curd-windows-build.iss
│ ├── release
│ └── requirements.txt
├── LICENSE
├── PKGBUILD
├── README.md
├── VERSION.txt
├── cmd/
│ └── curd/
│ └── main.go
├── flake.nix
├── go.mod
├── go.sum
├── internal/
│ ├── anilist.go
│ ├── anilist_cache.go
│ ├── anime_list.go
│ ├── aniskip.go
│ ├── config.go
│ ├── curd.go
│ ├── discord.go
│ ├── episode_list.go
│ ├── episode_url.go
│ ├── filler_list.go
│ ├── globals.go
│ ├── http_client.go
│ ├── jikan.go
│ ├── links.go
│ ├── localTracking.go
│ ├── player.go
│ ├── provider.go
│ ├── provider_allanime.go
│ ├── provider_animepahe.go
│ ├── rofi.go
│ ├── selection_menu.go
│ ├── structs.go
│ ├── unix_ipc.go
│ └── windows_ipc.go
├── package.nix
├── rofi/
│ ├── contextselect.rasi
│ ├── selectanime.rasi
│ ├── selectanimepreview.rasi
│ └── userinput.rasi
└── vendor/
├── github.com/
│ ├── Microsoft/
│ │ └── go-winio/
│ │ ├── .gitattributes
│ │ ├── .golangci.yml
│ │ ├── CODEOWNERS
│ │ ├── LICENSE
│ │ ├── README.md
│ │ ├── SECURITY.md
│ │ ├── backup.go
│ │ ├── doc.go
│ │ ├── ea.go
│ │ ├── file.go
│ │ ├── fileinfo.go
│ │ ├── hvsock.go
│ │ ├── internal/
│ │ │ ├── fs/
│ │ │ │ ├── doc.go
│ │ │ │ ├── fs.go
│ │ │ │ ├── security.go
│ │ │ │ └── zsyscall_windows.go
│ │ │ ├── socket/
│ │ │ │ ├── rawaddr.go
│ │ │ │ ├── socket.go
│ │ │ │ └── zsyscall_windows.go
│ │ │ └── stringbuffer/
│ │ │ └── wstring.go
│ │ ├── pipe.go
│ │ ├── pkg/
│ │ │ └── guid/
│ │ │ ├── guid.go
│ │ │ ├── guid_nonwindows.go
│ │ │ ├── guid_windows.go
│ │ │ └── variant_string.go
│ │ ├── privilege.go
│ │ ├── reparse.go
│ │ ├── sd.go
│ │ ├── syscall.go
│ │ └── zsyscall_windows.go
│ ├── aymanbagabas/
│ │ └── go-osc52/
│ │ └── v2/
│ │ ├── LICENSE
│ │ ├── README.md
│ │ └── osc52.go
│ ├── charmbracelet/
│ │ ├── bubbletea/
│ │ │ ├── .gitattributes
│ │ │ ├── .golangci-soft.yml
│ │ │ ├── .golangci.yml
│ │ │ ├── .goreleaser.yml
│ │ │ ├── LICENSE
│ │ │ ├── README.md
│ │ │ ├── commands.go
│ │ │ ├── exec.go
│ │ │ ├── focus.go
│ │ │ ├── inputreader_other.go
│ │ │ ├── inputreader_windows.go
│ │ │ ├── key.go
│ │ │ ├── key_other.go
│ │ │ ├── key_sequences.go
│ │ │ ├── key_windows.go
│ │ │ ├── logging.go
│ │ │ ├── mouse.go
│ │ │ ├── nil_renderer.go
│ │ │ ├── options.go
│ │ │ ├── renderer.go
│ │ │ ├── screen.go
│ │ │ ├── signals_unix.go
│ │ │ ├── signals_windows.go
│ │ │ ├── standard_renderer.go
│ │ │ ├── tea.go
│ │ │ ├── tea_init.go
│ │ │ ├── tty.go
│ │ │ ├── tty_unix.go
│ │ │ └── tty_windows.go
│ │ ├── lipgloss/
│ │ │ ├── .golangci-soft.yml
│ │ │ ├── .golangci.yml
│ │ │ ├── .goreleaser.yml
│ │ │ ├── LICENSE
│ │ │ ├── README.md
│ │ │ ├── align.go
│ │ │ ├── ansi_unix.go
│ │ │ ├── ansi_windows.go
│ │ │ ├── borders.go
│ │ │ ├── color.go
│ │ │ ├── get.go
│ │ │ ├── join.go
│ │ │ ├── position.go
│ │ │ ├── renderer.go
│ │ │ ├── runes.go
│ │ │ ├── set.go
│ │ │ ├── size.go
│ │ │ ├── style.go
│ │ │ ├── unset.go
│ │ │ └── whitespace.go
│ │ └── x/
│ │ ├── ansi/
│ │ │ ├── LICENSE
│ │ │ ├── ansi.go
│ │ │ ├── ascii.go
│ │ │ ├── background.go
│ │ │ ├── c0.go
│ │ │ ├── c1.go
│ │ │ ├── charset.go
│ │ │ ├── clipboard.go
│ │ │ ├── color.go
│ │ │ ├── ctrl.go
│ │ │ ├── cursor.go
│ │ │ ├── cwd.go
│ │ │ ├── doc.go
│ │ │ ├── focus.go
│ │ │ ├── graphics.go
│ │ │ ├── hyperlink.go
│ │ │ ├── iterm2.go
│ │ │ ├── keypad.go
│ │ │ ├── kitty/
│ │ │ │ ├── decoder.go
│ │ │ │ ├── encoder.go
│ │ │ │ ├── graphics.go
│ │ │ │ └── options.go
│ │ │ ├── kitty.go
│ │ │ ├── method.go
│ │ │ ├── mode.go
│ │ │ ├── modes.go
│ │ │ ├── mouse.go
│ │ │ ├── notification.go
│ │ │ ├── parser/
│ │ │ │ ├── const.go
│ │ │ │ ├── seq.go
│ │ │ │ └── transition_table.go
│ │ │ ├── parser.go
│ │ │ ├── parser_decode.go
│ │ │ ├── parser_handler.go
│ │ │ ├── parser_sync.go
│ │ │ ├── passthrough.go
│ │ │ ├── paste.go
│ │ │ ├── reset.go
│ │ │ ├── screen.go
│ │ │ ├── sgr.go
│ │ │ ├── status.go
│ │ │ ├── style.go
│ │ │ ├── termcap.go
│ │ │ ├── title.go
│ │ │ ├── truncate.go
│ │ │ ├── util.go
│ │ │ ├── width.go
│ │ │ ├── winop.go
│ │ │ ├── wrap.go
│ │ │ └── xterm.go
│ │ └── term/
│ │ ├── LICENSE
│ │ ├── term.go
│ │ ├── term_other.go
│ │ ├── term_unix.go
│ │ ├── term_unix_bsd.go
│ │ ├── term_unix_other.go
│ │ ├── term_windows.go
│ │ ├── terminal.go
│ │ └── util.go
│ ├── erikgeiser/
│ │ └── coninput/
│ │ ├── .golangci.yml
│ │ ├── LICENSE
│ │ ├── README.md
│ │ ├── keycodes.go
│ │ ├── mode.go
│ │ ├── read.go
│ │ └── records.go
│ ├── gen2brain/
│ │ └── beeep/
│ │ ├── LICENSE
│ │ ├── README.md
│ │ ├── alert_darwin.go
│ │ ├── alert_js.go
│ │ ├── alert_unix.go
│ │ ├── alert_unsupported.go
│ │ ├── alert_windows.go
│ │ ├── beeep.go
│ │ ├── beep_darwin.go
│ │ ├── beep_js.go
│ │ ├── beep_unix.go
│ │ ├── beep_unsupported.go
│ │ ├── beep_windows.go
│ │ ├── notify_darwin.go
│ │ ├── notify_js.go
│ │ ├── notify_unix.go
│ │ ├── notify_unix_nodbus.go
│ │ ├── notify_unsupported.go
│ │ └── notify_windows.go
│ ├── go-rod/
│ │ └── rod/
│ │ ├── .eslintrc.yml
│ │ ├── .golangci.yml
│ │ ├── .prettierrc.yml
│ │ ├── LICENSE
│ │ ├── README.md
│ │ ├── browser.go
│ │ ├── context.go
│ │ ├── dev_helpers.go
│ │ ├── element.go
│ │ ├── error.go
│ │ ├── go.work
│ │ ├── go.work.sum
│ │ ├── hijack.go
│ │ ├── input.go
│ │ ├── lib/
│ │ │ ├── assets/
│ │ │ │ ├── README.md
│ │ │ │ ├── assets.go
│ │ │ │ ├── monitor-page.html
│ │ │ │ └── monitor.html
│ │ │ ├── cdp/
│ │ │ │ ├── README.md
│ │ │ │ ├── client.go
│ │ │ │ ├── error.go
│ │ │ │ ├── format.go
│ │ │ │ ├── utils.go
│ │ │ │ └── websocket.go
│ │ │ ├── defaults/
│ │ │ │ └── defaults.go
│ │ │ ├── devices/
│ │ │ │ ├── device.go
│ │ │ │ ├── list.go
│ │ │ │ └── utils.go
│ │ │ ├── input/
│ │ │ │ ├── README.md
│ │ │ │ ├── keyboard.go
│ │ │ │ ├── keymap.go
│ │ │ │ ├── mac_comands.go
│ │ │ │ └── mouse.go
│ │ │ ├── js/
│ │ │ │ ├── helper.go
│ │ │ │ ├── helper.js
│ │ │ │ └── js.go
│ │ │ ├── launcher/
│ │ │ │ ├── README.md
│ │ │ │ ├── browser.go
│ │ │ │ ├── error.go
│ │ │ │ ├── flags/
│ │ │ │ │ └── flags.go
│ │ │ │ ├── launcher.go
│ │ │ │ ├── manager.go
│ │ │ │ ├── os_unix.go
│ │ │ │ ├── os_windows.go
│ │ │ │ ├── revision.go
│ │ │ │ ├── url_parser.go
│ │ │ │ └── utils.go
│ │ │ ├── proto/
│ │ │ │ ├── README.md
│ │ │ │ ├── a_interface.go
│ │ │ │ ├── a_patch.go
│ │ │ │ ├── a_utils.go
│ │ │ │ ├── accessibility.go
│ │ │ │ ├── animation.go
│ │ │ │ ├── audits.go
│ │ │ │ ├── autofill.go
│ │ │ │ ├── background_service.go
│ │ │ │ ├── browser.go
│ │ │ │ ├── cache_storage.go
│ │ │ │ ├── cast.go
│ │ │ │ ├── console.go
│ │ │ │ ├── css.go
│ │ │ │ ├── database.go
│ │ │ │ ├── debugger.go
│ │ │ │ ├── definitions.go
│ │ │ │ ├── device_access.go
│ │ │ │ ├── device_orientation.go
│ │ │ │ ├── dom.go
│ │ │ │ ├── dom_debugger.go
│ │ │ │ ├── dom_snapshot.go
│ │ │ │ ├── dom_storage.go
│ │ │ │ ├── emulation.go
│ │ │ │ ├── event_breakpoints.go
│ │ │ │ ├── extensions.go
│ │ │ │ ├── fed_cm.go
│ │ │ │ ├── fetch.go
│ │ │ │ ├── headless_experimental.go
│ │ │ │ ├── heap_profiler.go
│ │ │ │ ├── indexed_db.go
│ │ │ │ ├── input.go
│ │ │ │ ├── inspector.go
│ │ │ │ ├── io.go
│ │ │ │ ├── layer_tree.go
│ │ │ │ ├── log.go
│ │ │ │ ├── media.go
│ │ │ │ ├── memory.go
│ │ │ │ ├── network.go
│ │ │ │ ├── overlay.go
│ │ │ │ ├── page.go
│ │ │ │ ├── performance.go
│ │ │ │ ├── performance_timeline.go
│ │ │ │ ├── preload.go
│ │ │ │ ├── profiler.go
│ │ │ │ ├── pwa.go
│ │ │ │ ├── runtime.go
│ │ │ │ ├── schema.go
│ │ │ │ ├── security.go
│ │ │ │ ├── service_worker.go
│ │ │ │ ├── storage.go
│ │ │ │ ├── system_info.go
│ │ │ │ ├── target.go
│ │ │ │ ├── tethering.go
│ │ │ │ ├── tracing.go
│ │ │ │ ├── web_audio.go
│ │ │ │ └── web_authn.go
│ │ │ └── utils/
│ │ │ ├── imageutil.go
│ │ │ ├── sleeper.go
│ │ │ └── utils.go
│ │ ├── must.go
│ │ ├── page.go
│ │ ├── page_eval.go
│ │ ├── query.go
│ │ ├── states.go
│ │ └── utils.go
│ ├── go-toast/
│ │ └── toast/
│ │ ├── LICENSE
│ │ ├── readme.md
│ │ └── toast.go
│ ├── godbus/
│ │ └── dbus/
│ │ └── v5/
│ │ ├── CONTRIBUTING.md
│ │ ├── LICENSE
│ │ ├── MAINTAINERS
│ │ ├── README.md
│ │ ├── auth.go
│ │ ├── auth_anonymous.go
│ │ ├── auth_external.go
│ │ ├── auth_sha1.go
│ │ ├── call.go
│ │ ├── conn.go
│ │ ├── conn_darwin.go
│ │ ├── conn_other.go
│ │ ├── conn_unix.go
│ │ ├── conn_windows.go
│ │ ├── dbus.go
│ │ ├── decoder.go
│ │ ├── default_handler.go
│ │ ├── doc.go
│ │ ├── encoder.go
│ │ ├── escape.go
│ │ ├── export.go
│ │ ├── homedir.go
│ │ ├── match.go
│ │ ├── message.go
│ │ ├── object.go
│ │ ├── sequence.go
│ │ ├── sequential_handler.go
│ │ ├── server_interfaces.go
│ │ ├── sig.go
│ │ ├── transport_darwin.go
│ │ ├── transport_generic.go
│ │ ├── transport_nonce_tcp.go
│ │ ├── transport_tcp.go
│ │ ├── transport_unix.go
│ │ ├── transport_unixcred_dragonfly.go
│ │ ├── transport_unixcred_freebsd.go
│ │ ├── transport_unixcred_linux.go
│ │ ├── transport_unixcred_netbsd.go
│ │ ├── transport_unixcred_openbsd.go
│ │ ├── transport_zos.go
│ │ ├── variant.go
│ │ ├── variant_lexer.go
│ │ └── variant_parser.go
│ ├── lucasb-eyer/
│ │ └── go-colorful/
│ │ ├── CHANGELOG.md
│ │ ├── LICENSE
│ │ ├── README.md
│ │ ├── colorgens.go
│ │ ├── colors.go
│ │ ├── happy_palettegen.go
│ │ ├── hexcolor.go
│ │ ├── hsluv-snapshot-rev4.json
│ │ ├── hsluv.go
│ │ ├── soft_palettegen.go
│ │ └── warm_palettegen.go
│ ├── mattn/
│ │ ├── go-isatty/
│ │ │ ├── LICENSE
│ │ │ ├── README.md
│ │ │ ├── doc.go
│ │ │ ├── go.test.sh
│ │ │ ├── isatty_bsd.go
│ │ │ ├── isatty_others.go
│ │ │ ├── isatty_plan9.go
│ │ │ ├── isatty_solaris.go
│ │ │ ├── isatty_tcgets.go
│ │ │ └── isatty_windows.go
│ │ ├── go-localereader/
│ │ │ ├── README.md
│ │ │ ├── localereader.go
│ │ │ ├── localereader_unix.go
│ │ │ └── localereader_windows.go
│ │ └── go-runewidth/
│ │ ├── LICENSE
│ │ ├── README.md
│ │ ├── runewidth.go
│ │ ├── runewidth_appengine.go
│ │ ├── runewidth_js.go
│ │ ├── runewidth_posix.go
│ │ ├── runewidth_table.go
│ │ └── runewidth_windows.go
│ ├── muesli/
│ │ ├── ansi/
│ │ │ ├── .golangci.yml
│ │ │ ├── LICENSE
│ │ │ ├── README.md
│ │ │ ├── ansi.go
│ │ │ ├── buffer.go
│ │ │ ├── compressor/
│ │ │ │ └── writer.go
│ │ │ └── writer.go
│ │ ├── cancelreader/
│ │ │ ├── .golangci-soft.yml
│ │ │ ├── .golangci.yml
│ │ │ ├── LICENSE
│ │ │ ├── README.md
│ │ │ ├── cancelreader.go
│ │ │ ├── cancelreader_bsd.go
│ │ │ ├── cancelreader_default.go
│ │ │ ├── cancelreader_linux.go
│ │ │ ├── cancelreader_select.go
│ │ │ ├── cancelreader_unix.go
│ │ │ └── cancelreader_windows.go
│ │ └── termenv/
│ │ ├── .golangci-soft.yml
│ │ ├── .golangci.yml
│ │ ├── LICENSE
│ │ ├── README.md
│ │ ├── ansi_compat.md
│ │ ├── ansicolors.go
│ │ ├── color.go
│ │ ├── constants_linux.go
│ │ ├── constants_solaris.go
│ │ ├── constants_unix.go
│ │ ├── copy.go
│ │ ├── hyperlink.go
│ │ ├── notification.go
│ │ ├── output.go
│ │ ├── profile.go
│ │ ├── screen.go
│ │ ├── style.go
│ │ ├── templatehelper.go
│ │ ├── termenv.go
│ │ ├── termenv_other.go
│ │ ├── termenv_posix.go
│ │ ├── termenv_solaris.go
│ │ ├── termenv_unix.go
│ │ └── termenv_windows.go
│ ├── nu7hatch/
│ │ └── gouuid/
│ │ ├── COPYING
│ │ ├── README.md
│ │ └── uuid.go
│ ├── pkg/
│ │ └── browser/
│ │ ├── LICENSE
│ │ ├── README.md
│ │ ├── browser.go
│ │ ├── browser_darwin.go
│ │ ├── browser_freebsd.go
│ │ ├── browser_linux.go
│ │ ├── browser_netbsd.go
│ │ ├── browser_openbsd.go
│ │ ├── browser_unsupported.go
│ │ └── browser_windows.go
│ ├── rivo/
│ │ └── uniseg/
│ │ ├── LICENSE.txt
│ │ ├── README.md
│ │ ├── doc.go
│ │ ├── eastasianwidth.go
│ │ ├── emojipresentation.go
│ │ ├── gen_breaktest.go
│ │ ├── gen_properties.go
│ │ ├── grapheme.go
│ │ ├── graphemeproperties.go
│ │ ├── graphemerules.go
│ │ ├── line.go
│ │ ├── lineproperties.go
│ │ ├── linerules.go
│ │ ├── properties.go
│ │ ├── sentence.go
│ │ ├── sentenceproperties.go
│ │ ├── sentencerules.go
│ │ ├── step.go
│ │ ├── width.go
│ │ ├── word.go
│ │ ├── wordproperties.go
│ │ └── wordrules.go
│ ├── tadvi/
│ │ └── systray/
│ │ ├── AUTHORS
│ │ ├── LICENSE
│ │ ├── README.md
│ │ ├── systray_linux.go
│ │ └── systray_windows.go
│ ├── tr1xem/
│ │ └── go-discordrpc/
│ │ ├── LICENSE
│ │ ├── client/
│ │ │ ├── client.go
│ │ │ ├── inputMapper.go
│ │ │ └── types.go
│ │ └── internal/
│ │ └── ipc/
│ │ ├── ipc.go
│ │ ├── ipc_unix.go
│ │ └── ipc_windows.go
│ └── ysmood/
│ ├── fetchup/
│ │ ├── LICENSE
│ │ ├── README.md
│ │ ├── download.go
│ │ ├── events.go
│ │ ├── fetchup.go
│ │ └── utils.go
│ ├── goob/
│ │ ├── .golangci.yml
│ │ ├── LICENSE
│ │ ├── goob.go
│ │ ├── pipe.go
│ │ └── readme.md
│ ├── got/
│ │ ├── LICENSE
│ │ └── lib/
│ │ └── lcs/
│ │ ├── lcs.go
│ │ ├── sequence.go
│ │ └── utils.go
│ ├── gson/
│ │ ├── LICENSE
│ │ ├── README.md
│ │ ├── read.go
│ │ └── write.go
│ └── leakless/
│ ├── .golangci.yml
│ ├── LICENSE
│ ├── bin_amd64_darwin.go
│ ├── bin_amd64_linux.go
│ ├── bin_amd64_windows.go
│ ├── bin_arm64_darwin.go
│ ├── bin_arm64_linux.go
│ ├── leakless.go
│ ├── pkg/
│ │ ├── shared/
│ │ │ ├── message.go
│ │ │ └── version.go
│ │ └── utils/
│ │ ├── target.go
│ │ └── utils.go
│ └── readme.md
├── golang.org/
│ └── x/
│ ├── sync/
│ │ ├── LICENSE
│ │ ├── PATENTS
│ │ └── errgroup/
│ │ ├── errgroup.go
│ │ ├── go120.go
│ │ └── pre_go120.go
│ ├── sys/
│ │ ├── LICENSE
│ │ ├── PATENTS
│ │ ├── unix/
│ │ │ ├── README.md
│ │ │ ├── affinity_linux.go
│ │ │ ├── aliases.go
│ │ │ ├── asm_aix_ppc64.s
│ │ │ ├── asm_bsd_386.s
│ │ │ ├── asm_bsd_amd64.s
│ │ │ ├── asm_bsd_arm.s
│ │ │ ├── asm_bsd_arm64.s
│ │ │ ├── asm_bsd_ppc64.s
│ │ │ ├── asm_bsd_riscv64.s
│ │ │ ├── asm_linux_386.s
│ │ │ ├── asm_linux_amd64.s
│ │ │ ├── asm_linux_arm.s
│ │ │ ├── asm_linux_arm64.s
│ │ │ ├── asm_linux_loong64.s
│ │ │ ├── asm_linux_mips64x.s
│ │ │ ├── asm_linux_mipsx.s
│ │ │ ├── asm_linux_ppc64x.s
│ │ │ ├── asm_linux_riscv64.s
│ │ │ ├── asm_linux_s390x.s
│ │ │ ├── asm_openbsd_mips64.s
│ │ │ ├── asm_solaris_amd64.s
│ │ │ ├── asm_zos_s390x.s
│ │ │ ├── auxv.go
│ │ │ ├── auxv_unsupported.go
│ │ │ ├── bluetooth_linux.go
│ │ │ ├── bpxsvc_zos.go
│ │ │ ├── bpxsvc_zos.s
│ │ │ ├── cap_freebsd.go
│ │ │ ├── constants.go
│ │ │ ├── dev_aix_ppc.go
│ │ │ ├── dev_aix_ppc64.go
│ │ │ ├── dev_darwin.go
│ │ │ ├── dev_dragonfly.go
│ │ │ ├── dev_freebsd.go
│ │ │ ├── dev_linux.go
│ │ │ ├── dev_netbsd.go
│ │ │ ├── dev_openbsd.go
│ │ │ ├── dev_zos.go
│ │ │ ├── dirent.go
│ │ │ ├── endian_big.go
│ │ │ ├── endian_little.go
│ │ │ ├── env_unix.go
│ │ │ ├── fcntl.go
│ │ │ ├── fcntl_darwin.go
│ │ │ ├── fcntl_linux_32bit.go
│ │ │ ├── fdset.go
│ │ │ ├── gccgo.go
│ │ │ ├── gccgo_c.c
│ │ │ ├── gccgo_linux_amd64.go
│ │ │ ├── ifreq_linux.go
│ │ │ ├── ioctl_linux.go
│ │ │ ├── ioctl_signed.go
│ │ │ ├── ioctl_unsigned.go
│ │ │ ├── ioctl_zos.go
│ │ │ ├── mkall.sh
│ │ │ ├── mkerrors.sh
│ │ │ ├── mmap_nomremap.go
│ │ │ ├── mremap.go
│ │ │ ├── pagesize_unix.go
│ │ │ ├── pledge_openbsd.go
│ │ │ ├── ptrace_darwin.go
│ │ │ ├── ptrace_ios.go
│ │ │ ├── race.go
│ │ │ ├── race0.go
│ │ │ ├── readdirent_getdents.go
│ │ │ ├── readdirent_getdirentries.go
│ │ │ ├── sockcmsg_dragonfly.go
│ │ │ ├── sockcmsg_linux.go
│ │ │ ├── sockcmsg_unix.go
│ │ │ ├── sockcmsg_unix_other.go
│ │ │ ├── sockcmsg_zos.go
│ │ │ ├── symaddr_zos_s390x.s
│ │ │ ├── syscall.go
│ │ │ ├── syscall_aix.go
│ │ │ ├── syscall_aix_ppc.go
│ │ │ ├── syscall_aix_ppc64.go
│ │ │ ├── syscall_bsd.go
│ │ │ ├── syscall_darwin.go
│ │ │ ├── syscall_darwin_amd64.go
│ │ │ ├── syscall_darwin_arm64.go
│ │ │ ├── syscall_darwin_libSystem.go
│ │ │ ├── syscall_dragonfly.go
│ │ │ ├── syscall_dragonfly_amd64.go
│ │ │ ├── syscall_freebsd.go
│ │ │ ├── syscall_freebsd_386.go
│ │ │ ├── syscall_freebsd_amd64.go
│ │ │ ├── syscall_freebsd_arm.go
│ │ │ ├── syscall_freebsd_arm64.go
│ │ │ ├── syscall_freebsd_riscv64.go
│ │ │ ├── syscall_hurd.go
│ │ │ ├── syscall_hurd_386.go
│ │ │ ├── syscall_illumos.go
│ │ │ ├── syscall_linux.go
│ │ │ ├── syscall_linux_386.go
│ │ │ ├── syscall_linux_alarm.go
│ │ │ ├── syscall_linux_amd64.go
│ │ │ ├── syscall_linux_amd64_gc.go
│ │ │ ├── syscall_linux_arm.go
│ │ │ ├── syscall_linux_arm64.go
│ │ │ ├── syscall_linux_gc.go
│ │ │ ├── syscall_linux_gc_386.go
│ │ │ ├── syscall_linux_gc_arm.go
│ │ │ ├── syscall_linux_gccgo_386.go
│ │ │ ├── syscall_linux_gccgo_arm.go
│ │ │ ├── syscall_linux_loong64.go
│ │ │ ├── syscall_linux_mips64x.go
│ │ │ ├── syscall_linux_mipsx.go
│ │ │ ├── syscall_linux_ppc.go
│ │ │ ├── syscall_linux_ppc64x.go
│ │ │ ├── syscall_linux_riscv64.go
│ │ │ ├── syscall_linux_s390x.go
│ │ │ ├── syscall_linux_sparc64.go
│ │ │ ├── syscall_netbsd.go
│ │ │ ├── syscall_netbsd_386.go
│ │ │ ├── syscall_netbsd_amd64.go
│ │ │ ├── syscall_netbsd_arm.go
│ │ │ ├── syscall_netbsd_arm64.go
│ │ │ ├── syscall_openbsd.go
│ │ │ ├── syscall_openbsd_386.go
│ │ │ ├── syscall_openbsd_amd64.go
│ │ │ ├── syscall_openbsd_arm.go
│ │ │ ├── syscall_openbsd_arm64.go
│ │ │ ├── syscall_openbsd_libc.go
│ │ │ ├── syscall_openbsd_mips64.go
│ │ │ ├── syscall_openbsd_ppc64.go
│ │ │ ├── syscall_openbsd_riscv64.go
│ │ │ ├── syscall_solaris.go
│ │ │ ├── syscall_solaris_amd64.go
│ │ │ ├── syscall_unix.go
│ │ │ ├── syscall_unix_gc.go
│ │ │ ├── syscall_unix_gc_ppc64x.go
│ │ │ ├── syscall_zos_s390x.go
│ │ │ ├── sysvshm_linux.go
│ │ │ ├── sysvshm_unix.go
│ │ │ ├── sysvshm_unix_other.go
│ │ │ ├── timestruct.go
│ │ │ ├── unveil_openbsd.go
│ │ │ ├── vgetrandom_linux.go
│ │ │ ├── vgetrandom_unsupported.go
│ │ │ ├── xattr_bsd.go
│ │ │ ├── zerrors_aix_ppc.go
│ │ │ ├── zerrors_aix_ppc64.go
│ │ │ ├── zerrors_darwin_amd64.go
│ │ │ ├── zerrors_darwin_arm64.go
│ │ │ ├── zerrors_dragonfly_amd64.go
│ │ │ ├── zerrors_freebsd_386.go
│ │ │ ├── zerrors_freebsd_amd64.go
│ │ │ ├── zerrors_freebsd_arm.go
│ │ │ ├── zerrors_freebsd_arm64.go
│ │ │ ├── zerrors_freebsd_riscv64.go
│ │ │ ├── zerrors_linux.go
│ │ │ ├── zerrors_linux_386.go
│ │ │ ├── zerrors_linux_amd64.go
│ │ │ ├── zerrors_linux_arm.go
│ │ │ ├── zerrors_linux_arm64.go
│ │ │ ├── zerrors_linux_loong64.go
│ │ │ ├── zerrors_linux_mips.go
│ │ │ ├── zerrors_linux_mips64.go
│ │ │ ├── zerrors_linux_mips64le.go
│ │ │ ├── zerrors_linux_mipsle.go
│ │ │ ├── zerrors_linux_ppc.go
│ │ │ ├── zerrors_linux_ppc64.go
│ │ │ ├── zerrors_linux_ppc64le.go
│ │ │ ├── zerrors_linux_riscv64.go
│ │ │ ├── zerrors_linux_s390x.go
│ │ │ ├── zerrors_linux_sparc64.go
│ │ │ ├── zerrors_netbsd_386.go
│ │ │ ├── zerrors_netbsd_amd64.go
│ │ │ ├── zerrors_netbsd_arm.go
│ │ │ ├── zerrors_netbsd_arm64.go
│ │ │ ├── zerrors_openbsd_386.go
│ │ │ ├── zerrors_openbsd_amd64.go
│ │ │ ├── zerrors_openbsd_arm.go
│ │ │ ├── zerrors_openbsd_arm64.go
│ │ │ ├── zerrors_openbsd_mips64.go
│ │ │ ├── zerrors_openbsd_ppc64.go
│ │ │ ├── zerrors_openbsd_riscv64.go
│ │ │ ├── zerrors_solaris_amd64.go
│ │ │ ├── zerrors_zos_s390x.go
│ │ │ ├── zptrace_armnn_linux.go
│ │ │ ├── zptrace_linux_arm64.go
│ │ │ ├── zptrace_mipsnn_linux.go
│ │ │ ├── zptrace_mipsnnle_linux.go
│ │ │ ├── zptrace_x86_linux.go
│ │ │ ├── zsymaddr_zos_s390x.s
│ │ │ ├── zsyscall_aix_ppc.go
│ │ │ ├── zsyscall_aix_ppc64.go
│ │ │ ├── zsyscall_aix_ppc64_gc.go
│ │ │ ├── zsyscall_aix_ppc64_gccgo.go
│ │ │ ├── zsyscall_darwin_amd64.go
│ │ │ ├── zsyscall_darwin_amd64.s
│ │ │ ├── zsyscall_darwin_arm64.go
│ │ │ ├── zsyscall_darwin_arm64.s
│ │ │ ├── zsyscall_dragonfly_amd64.go
│ │ │ ├── zsyscall_freebsd_386.go
│ │ │ ├── zsyscall_freebsd_amd64.go
│ │ │ ├── zsyscall_freebsd_arm.go
│ │ │ ├── zsyscall_freebsd_arm64.go
│ │ │ ├── zsyscall_freebsd_riscv64.go
│ │ │ ├── zsyscall_illumos_amd64.go
│ │ │ ├── zsyscall_linux.go
│ │ │ ├── zsyscall_linux_386.go
│ │ │ ├── zsyscall_linux_amd64.go
│ │ │ ├── zsyscall_linux_arm.go
│ │ │ ├── zsyscall_linux_arm64.go
│ │ │ ├── zsyscall_linux_loong64.go
│ │ │ ├── zsyscall_linux_mips.go
│ │ │ ├── zsyscall_linux_mips64.go
│ │ │ ├── zsyscall_linux_mips64le.go
│ │ │ ├── zsyscall_linux_mipsle.go
│ │ │ ├── zsyscall_linux_ppc.go
│ │ │ ├── zsyscall_linux_ppc64.go
│ │ │ ├── zsyscall_linux_ppc64le.go
│ │ │ ├── zsyscall_linux_riscv64.go
│ │ │ ├── zsyscall_linux_s390x.go
│ │ │ ├── zsyscall_linux_sparc64.go
│ │ │ ├── zsyscall_netbsd_386.go
│ │ │ ├── zsyscall_netbsd_amd64.go
│ │ │ ├── zsyscall_netbsd_arm.go
│ │ │ ├── zsyscall_netbsd_arm64.go
│ │ │ ├── zsyscall_openbsd_386.go
│ │ │ ├── zsyscall_openbsd_386.s
│ │ │ ├── zsyscall_openbsd_amd64.go
│ │ │ ├── zsyscall_openbsd_amd64.s
│ │ │ ├── zsyscall_openbsd_arm.go
│ │ │ ├── zsyscall_openbsd_arm.s
│ │ │ ├── zsyscall_openbsd_arm64.go
│ │ │ ├── zsyscall_openbsd_arm64.s
│ │ │ ├── zsyscall_openbsd_mips64.go
│ │ │ ├── zsyscall_openbsd_mips64.s
│ │ │ ├── zsyscall_openbsd_ppc64.go
│ │ │ ├── zsyscall_openbsd_ppc64.s
│ │ │ ├── zsyscall_openbsd_riscv64.go
│ │ │ ├── zsyscall_openbsd_riscv64.s
│ │ │ ├── zsyscall_solaris_amd64.go
│ │ │ ├── zsyscall_zos_s390x.go
│ │ │ ├── zsysctl_openbsd_386.go
│ │ │ ├── zsysctl_openbsd_amd64.go
│ │ │ ├── zsysctl_openbsd_arm.go
│ │ │ ├── zsysctl_openbsd_arm64.go
│ │ │ ├── zsysctl_openbsd_mips64.go
│ │ │ ├── zsysctl_openbsd_ppc64.go
│ │ │ ├── zsysctl_openbsd_riscv64.go
│ │ │ ├── zsysnum_darwin_amd64.go
│ │ │ ├── zsysnum_darwin_arm64.go
│ │ │ ├── zsysnum_dragonfly_amd64.go
│ │ │ ├── zsysnum_freebsd_386.go
│ │ │ ├── zsysnum_freebsd_amd64.go
│ │ │ ├── zsysnum_freebsd_arm.go
│ │ │ ├── zsysnum_freebsd_arm64.go
│ │ │ ├── zsysnum_freebsd_riscv64.go
│ │ │ ├── zsysnum_linux_386.go
│ │ │ ├── zsysnum_linux_amd64.go
│ │ │ ├── zsysnum_linux_arm.go
│ │ │ ├── zsysnum_linux_arm64.go
│ │ │ ├── zsysnum_linux_loong64.go
│ │ │ ├── zsysnum_linux_mips.go
│ │ │ ├── zsysnum_linux_mips64.go
│ │ │ ├── zsysnum_linux_mips64le.go
│ │ │ ├── zsysnum_linux_mipsle.go
│ │ │ ├── zsysnum_linux_ppc.go
│ │ │ ├── zsysnum_linux_ppc64.go
│ │ │ ├── zsysnum_linux_ppc64le.go
│ │ │ ├── zsysnum_linux_riscv64.go
│ │ │ ├── zsysnum_linux_s390x.go
│ │ │ ├── zsysnum_linux_sparc64.go
│ │ │ ├── zsysnum_netbsd_386.go
│ │ │ ├── zsysnum_netbsd_amd64.go
│ │ │ ├── zsysnum_netbsd_arm.go
│ │ │ ├── zsysnum_netbsd_arm64.go
│ │ │ ├── zsysnum_openbsd_386.go
│ │ │ ├── zsysnum_openbsd_amd64.go
│ │ │ ├── zsysnum_openbsd_arm.go
│ │ │ ├── zsysnum_openbsd_arm64.go
│ │ │ ├── zsysnum_openbsd_mips64.go
│ │ │ ├── zsysnum_openbsd_ppc64.go
│ │ │ ├── zsysnum_openbsd_riscv64.go
│ │ │ ├── zsysnum_zos_s390x.go
│ │ │ ├── ztypes_aix_ppc.go
│ │ │ ├── ztypes_aix_ppc64.go
│ │ │ ├── ztypes_darwin_amd64.go
│ │ │ ├── ztypes_darwin_arm64.go
│ │ │ ├── ztypes_dragonfly_amd64.go
│ │ │ ├── ztypes_freebsd_386.go
│ │ │ ├── ztypes_freebsd_amd64.go
│ │ │ ├── ztypes_freebsd_arm.go
│ │ │ ├── ztypes_freebsd_arm64.go
│ │ │ ├── ztypes_freebsd_riscv64.go
│ │ │ ├── ztypes_linux.go
│ │ │ ├── ztypes_linux_386.go
│ │ │ ├── ztypes_linux_amd64.go
│ │ │ ├── ztypes_linux_arm.go
│ │ │ ├── ztypes_linux_arm64.go
│ │ │ ├── ztypes_linux_loong64.go
│ │ │ ├── ztypes_linux_mips.go
│ │ │ ├── ztypes_linux_mips64.go
│ │ │ ├── ztypes_linux_mips64le.go
│ │ │ ├── ztypes_linux_mipsle.go
│ │ │ ├── ztypes_linux_ppc.go
│ │ │ ├── ztypes_linux_ppc64.go
│ │ │ ├── ztypes_linux_ppc64le.go
│ │ │ ├── ztypes_linux_riscv64.go
│ │ │ ├── ztypes_linux_s390x.go
│ │ │ ├── ztypes_linux_sparc64.go
│ │ │ ├── ztypes_netbsd_386.go
│ │ │ ├── ztypes_netbsd_amd64.go
│ │ │ ├── ztypes_netbsd_arm.go
│ │ │ ├── ztypes_netbsd_arm64.go
│ │ │ ├── ztypes_openbsd_386.go
│ │ │ ├── ztypes_openbsd_amd64.go
│ │ │ ├── ztypes_openbsd_arm.go
│ │ │ ├── ztypes_openbsd_arm64.go
│ │ │ ├── ztypes_openbsd_mips64.go
│ │ │ ├── ztypes_openbsd_ppc64.go
│ │ │ ├── ztypes_openbsd_riscv64.go
│ │ │ ├── ztypes_solaris_amd64.go
│ │ │ └── ztypes_zos_s390x.go
│ │ └── windows/
│ │ ├── aliases.go
│ │ ├── dll_windows.go
│ │ ├── env_windows.go
│ │ ├── eventlog.go
│ │ ├── exec_windows.go
│ │ ├── memory_windows.go
│ │ ├── mkerrors.bash
│ │ ├── mkknownfolderids.bash
│ │ ├── mksyscall.go
│ │ ├── race.go
│ │ ├── race0.go
│ │ ├── registry/
│ │ │ ├── key.go
│ │ │ ├── mksyscall.go
│ │ │ ├── syscall.go
│ │ │ ├── value.go
│ │ │ └── zsyscall_windows.go
│ │ ├── security_windows.go
│ │ ├── service.go
│ │ ├── setupapi_windows.go
│ │ ├── str.go
│ │ ├── syscall.go
│ │ ├── syscall_windows.go
│ │ ├── types_windows.go
│ │ ├── types_windows_386.go
│ │ ├── types_windows_amd64.go
│ │ ├── types_windows_arm.go
│ │ ├── types_windows_arm64.go
│ │ ├── zerrors_windows.go
│ │ ├── zknownfolderids_windows.go
│ │ └── zsyscall_windows.go
│ └── text/
│ ├── LICENSE
│ ├── PATENTS
│ └── transform/
│ └── transform.go
├── gopkg.in/
│ └── natefinch/
│ └── npipe.v2/
│ ├── LICENSE.txt
│ ├── README.md
│ ├── doc.go
│ ├── npipe_windows.go
│ ├── znpipe_windows_386.go
│ └── znpipe_windows_amd64.go
└── modules.txt
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitattributes
================================================
Build/mpv.exe filter=lfs diff=lfs merge=lfs -text
================================================
FILE: .github/ISSUE_TEMPLATE/bug_report.md
================================================
---
name: Bug report
about: Create a report to help us improve
title: ''
labels: bug, help wanted
assignees: Wraient
---
**Describe the bug**
A clear and concise description of what the bug is.
**To Reproduce**
Steps to reproduce the behavior:
**Expected behavior**
A clear and concise description of what you expected to happen.
**Screenshots**
If applicable, add screenshots to help explain your problem.
**Environment (please complete the following information):**
- Distro: [e.g. Fedora, Arch]
**Debug logs**
Debug logs are located at ~/.local/share/curd/debug.log (for Linux)
or C:\.local\share\curd\debug.log (for windows)
**Optional context**
Add any other context about the problem here.
================================================
FILE: .github/workflows/ci-cd.yml
================================================
name: CI/CD Pipeline
on:
push:
branches:
- main # Trigger on pushes to the main branch
pull_request:
branches:
- main # Trigger on pull requests targeting the main branch
workflow_dispatch:
inputs:
pr_number:
description: 'Pull Request Number'
required: false
type: string
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0 # Fetch all history and tags
ref: ${{ github.event.pull_request.head.sha || (github.event.inputs.pr_number && format('refs/pull/{0}/head', github.event.inputs.pr_number)) || github.sha }}
- name: Set up Go
uses: actions/setup-go@v4
with:
go-version: '1.21'
- name: Install Dependencies
run: go mod tidy
- name: Build Linux binary
run: |
./Build/buildlinux
mkdir -p release/linux
mv curd-linux-x86_64 release/linux/
mv curd-linux-arm64 release/linux/
env:
GITHUB_EVENT_NAME: ${{ github.event_name }}
GITHUB_REF: ${{ github.ref }}
GITHUB_EVENT_HEAD_COMMIT_MESSAGE: ${{ github.event.head_commit.message }}
COMPRESS: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' && contains(github.event.head_commit.message, 'release:') }}
- name: Build macOS x86_64 binary
run: |
./Build/buildmac-x86_64
- name: Build macOS ARM64 binary
run: |
./Build/buildmac-arm64
- name: Install LLVM
run: |
sudo apt-get update && sudo apt-get install -y llvm
# Find the llvm-lipo command
LIPO_CMD=$(find /usr/bin -name "llvm-lipo*" | head -n 1)
echo "Found lipo command: $LIPO_CMD"
echo "LIPO_CMD=$LIPO_CMD" >> $GITHUB_ENV
- name: Create Universal macOS binary
run: |
${{ env.LIPO_CMD }} -create "curd-macos-x86_64" "curd-macos-arm64" -output "curd-macos-universal"
mkdir -p release/macos
mv curd-macos-x86_64 release/macos
mv curd-macos-arm64 release/macos
mv curd-macos-universal release/macos
- name: Build Windows binary (cross-compile)
run: |
./Build/buildwindows
mkdir -p release/windows
mv curd-windows-x86_64.exe release/windows/curd-windows-x86_64.exe
env:
GITHUB_EVENT_NAME: ${{ github.event_name }}
GITHUB_REF: ${{ github.ref }}
GITHUB_EVENT_HEAD_COMMIT_MESSAGE: ${{ github.event.head_commit.message }}
COMPRESS: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' && contains(github.event.head_commit.message, 'release:') }}
- name: Upload Artifacts
uses: actions/upload-artifact@v4
with:
name: curd-binaries
path: |
release/linux/curd-linux-x86_64
release/linux/curd-linux-arm64
release/macos/curd-macos-x86_64
release/macos/curd-macos-arm64
release/macos/curd-macos-universal
release/windows/curd-windows-x86_64.exe
retention-days: 1
if-no-files-found: error
release:
runs-on: windows-latest
needs: build
permissions:
contents: write
actions: read
if: |
github.ref == 'refs/heads/main' &&
github.event_name == 'push' &&
(contains(github.event.head_commit.message, 'release:'))
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Checkout MPV binaries
uses: actions/checkout@v4
with:
ref: mpv-binaries
path: mpv-temp
sparse-checkout: |
Build/mpv.exe.gz
Build/mpv.zip
- name: Setup MPV binary
run: |
New-Item -ItemType Directory -Force -Path "Build\mpv"
if (Test-Path "mpv-temp/Build/mpv.exe.gz") {
Copy-Item "mpv-temp/Build/mpv.exe.gz" "Build\mpv\mpv.exe.gz"
7z x "Build\mpv\mpv.exe.gz" -o"Build\mpv"
Remove-Item "Build\mpv\mpv.exe.gz"
} else {
Write-Host "Warning: MPV binary not found in mpv-binaries branch, downloading from URL..."
Invoke-WebRequest -Uri "https://raw.githubusercontent.com/${{ github.repository }}/main/Build/mpv.exe.gz" -OutFile "Build\mpv\mpv.exe.gz"
7z x "Build\mpv\mpv.exe.gz" -o"Build\mpv"
Remove-Item "Build\mpv\mpv.exe.gz"
}
Remove-Item -Recurse -Force "mpv-temp" -ErrorAction SilentlyContinue
shell: pwsh
- name: Download Artifacts
uses: actions/download-artifact@v4
with:
name: curd-binaries
path: Build
- name: Organize Release Files
run: |
$version = Get-Content VERSION.txt
echo "CURD_VERSION=$version" >> $env:GITHUB_ENV
$release_dir = "releases/curd-$version"
# Create directory structure
New-Item -ItemType Directory -Force -Path "$release_dir/windows"
New-Item -ItemType Directory -Force -Path "$release_dir/macos"
New-Item -ItemType Directory -Force -Path "$release_dir/linux"
# List contents of Build directory to debug
Write-Host "Contents of Build directory:"
Get-ChildItem -Path "Build" -Recurse
# Move files to their respective directories
Move-Item "Build/windows/curd-windows-x86_64.exe" "$release_dir/windows/"
Move-Item "Build/macos/curd-macos-universal" "$release_dir/macos/"
Move-Item "Build/macos/curd-macos-x86_64" "$release_dir/macos/"
Move-Item "Build/macos/curd-macos-arm64" "$release_dir/macos/"
Move-Item "Build/linux/curd-linux-x86_64" "$release_dir/linux/"
Move-Item "Build/linux/curd-linux-arm64" "$release_dir/linux/"
Copy-Item "Build/mpv/mpv.exe" "$release_dir/windows/"
shell: pwsh
- name: Update Inno Setup Script with New Version
run: |
$iss_path = "Build/curd-windows-build.iss"
$content = Get-Content $iss_path
$content = $content -replace '^AppVersion=.*', "AppVersion=$env:CURD_VERSION"
Set-Content $iss_path $content
shell: pwsh
- name: Create Windows Installer
run: |
& "C:\Program Files (x86)\Inno Setup 6\ISCC.exe" "Build\curd-windows-build.iss"
shell: pwsh
- name: Build direct commit release notes
run: |
$ErrorActionPreference = 'Stop'
$repo = "${{ github.repository }}"
$token = "${{ secrets.ACTIONS_PAT }}"
$headers = @{
Authorization = "Bearer $token"
Accept = "application/vnd.github+json"
"X-GitHub-Api-Version" = "2022-11-28"
}
$currentTag = "v$env:CURD_VERSION"
$tags = @(git tag --sort=-version:refname "v*")
$previousTag = $null
foreach ($tag in $tags) {
if ($tag -ne $currentTag) {
$previousTag = $tag
break
}
}
if ($previousTag) {
$range = "$previousTag..HEAD"
} else {
$rootCommit = (git rev-list --max-parents=0 HEAD | Select-Object -First 1)
if ([string]::IsNullOrWhiteSpace($rootCommit)) {
$range = "HEAD"
} else {
$range = "$rootCommit..HEAD"
}
}
$rawCommits = @(git log --no-merges --pretty=format:'%H%x09%s%x09%an' $range)
if ($rawCommits.Count -eq 1 -and [string]::IsNullOrWhiteSpace($rawCommits[0])) {
$rawCommits = @()
}
$directCommitLines = @()
$contributorSet = @{}
foreach ($entry in $rawCommits) {
$parts = $entry -split "`t", 3
if ($parts.Count -lt 3) {
continue
}
$sha = $parts[0].Trim()
$subject = $parts[1].Trim()
$authorName = $parts[2].Trim()
if ([string]::IsNullOrWhiteSpace($sha) -or [string]::IsNullOrWhiteSpace($subject)) {
continue
}
if ($subject -match '^\s*release:') {
continue
}
$pullsUri = "https://api.github.com/repos/$repo/commits/$sha/pulls"
$pulls = @()
try {
$pulls = @(Invoke-RestMethod -Uri $pullsUri -Headers $headers -Method Get)
} catch {
$pulls = @()
}
# Skip commits that are already represented by pull requests in generated notes.
if ($pulls.Count -gt 0) {
continue
}
$commitUri = "https://api.github.com/repos/$repo/commits/$sha"
$login = $null
try {
$commitData = Invoke-RestMethod -Uri $commitUri -Headers $headers -Method Get
if ($null -ne $commitData.author -and $null -ne $commitData.author.login) {
$login = $commitData.author.login
}
} catch {
$login = $null
}
$shortSha = $sha.Substring(0, 7)
if (-not [string]::IsNullOrWhiteSpace($login)) {
$authorDisplay = "[@$login](https://github.com/$login)"
} else {
$authorDisplay = $authorName
}
$contributorSet[$authorDisplay] = $true
$directCommitLines += "- $subject ([$shortSha](https://github.com/$repo/commit/$sha)) by $authorDisplay"
}
$notesPath = "Build/release-notes-extra.md"
$body = @()
$body += "## Direct Commits"
if ($directCommitLines.Count -eq 0) {
$body += "- No direct commits in this release range."
} else {
$body += $directCommitLines
}
$body += ""
$body += "## Direct Commit Contributors"
$contributors = @($contributorSet.Keys | Sort-Object)
if ($contributors.Count -eq 0) {
$body += "- None"
} else {
foreach ($contributor in $contributors) {
$body += "- $contributor"
}
}
if ($previousTag) {
$body += ""
$body += "_Range: $previousTag..HEAD_"
}
$body | Set-Content -Path $notesPath -Encoding utf8
shell: pwsh
- name: Create Release
id: create_release
uses: softprops/action-gh-release@v1
with:
tag_name: "v${{ env.CURD_VERSION }}"
name: "Curd v${{ env.CURD_VERSION }}"
draft: false
prerelease: false
generate_release_notes: true
body_path: Build/release-notes-extra.md
files: |
releases/curd-${{ env.CURD_VERSION }}/linux/curd-linux-x86_64
releases/curd-${{ env.CURD_VERSION }}/linux/curd-linux-arm64
releases/curd-${{ env.CURD_VERSION }}/macos/curd-macos-x86_64
releases/curd-${{ env.CURD_VERSION }}/macos/curd-macos-arm64
releases/curd-${{ env.CURD_VERSION }}/macos/curd-macos-universal
releases/curd-${{ env.CURD_VERSION }}/windows/curd-windows-x86_64.exe
Build/Output/curd-windows-installer.exe
env:
GITHUB_TOKEN: ${{ secrets.ACTIONS_PAT }}
================================================
FILE: .github/workflows/update-aur.yml
================================================
name: Update AUR Package
on:
release:
types: [published]
workflow_dispatch:
permissions:
contents: read
jobs:
update-aur:
runs-on: ubuntu-24.04
if: github.repository == 'Wraient/curd'
steps:
- name: Install dependencies
run: |
sudo apt-get update
sudo apt-get install -y curl git jq openssh-client
- name: Download release asset and compute SHA256
id: release
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
set -euo pipefail
if [ "${{ github.event_name }}" = "release" ]; then
TAG_NAME="${{ github.event.release.tag_name }}"
RELEASE_API_URL="https://api.github.com/repos/${{ github.repository }}/releases/tags/${TAG_NAME}"
else
RELEASE_API_URL="https://api.github.com/repos/${{ github.repository }}/releases/latest"
fi
RELEASE_JSON="$(mktemp)"
curl -fsSL \
-H "Authorization: Bearer ${GH_TOKEN}" \
-H "Accept: application/vnd.github+json" \
"$RELEASE_API_URL" \
-o "$RELEASE_JSON"
TAG_NAME="$(jq -r '.tag_name // empty' "$RELEASE_JSON")"
ASSET_URL="$(jq -r '.assets[] | select(.name=="curd-linux-x86_64") | .browser_download_url' "$RELEASE_JSON" | head -n1)"
if [ -z "$TAG_NAME" ] || [ "$TAG_NAME" = "null" ]; then
echo "Could not resolve release tag from $RELEASE_API_URL"
rm -f "$RELEASE_JSON"
exit 1
fi
if [ -z "$ASSET_URL" ] || [ "$ASSET_URL" = "null" ]; then
echo "Release ${TAG_NAME} does not contain asset: curd-linux-x86_64"
rm -f "$RELEASE_JSON"
exit 1
fi
VERSION="${TAG_NAME#v}"
TMP_ASSET="$(mktemp)"
curl -fL --retry 3 --retry-all-errors --connect-timeout 20 "$ASSET_URL" -o "$TMP_ASSET"
SHA256="$(sha256sum "$TMP_ASSET" | awk '{print $1}')"
rm -f "$RELEASE_JSON"
rm -f "$TMP_ASSET"
echo "version=$VERSION" >> "$GITHUB_OUTPUT"
echo "tag_name=$TAG_NAME" >> "$GITHUB_OUTPUT"
echo "sha256=$SHA256" >> "$GITHUB_OUTPUT"
- name: Configure SSH for AUR
env:
AUR_SSH_PRIVATE_KEY: ${{ secrets.AUR_SSH_PRIVATE_KEY }}
run: |
set -euo pipefail
if [ -z "${AUR_SSH_PRIVATE_KEY:-}" ]; then
echo "Missing required secret: AUR_SSH_PRIVATE_KEY"
exit 1
fi
install -m 700 -d ~/.ssh
umask 077
KEY_FILE=~/.ssh/curd_aur_deploy
RAW_KEY="$(printf '%s' "$AUR_SSH_PRIVATE_KEY" | tr -d '\r')"
if printf '%s' "$RAW_KEY" | grep -q 'BEGIN [A-Z0-9 ]*PRIVATE KEY'; then
if printf '%s' "$RAW_KEY" | grep -q '\\n'; then
printf '%b' "$RAW_KEY" > "$KEY_FILE"
else
printf '%s\n' "$RAW_KEY" > "$KEY_FILE"
fi
else
if ! printf '%s' "$RAW_KEY" | base64 -d > "$KEY_FILE" 2>/dev/null; then
echo "AUR_SSH_PRIVATE_KEY must be a private key (raw, escaped with \\n, or base64-encoded)"
exit 1
fi
fi
tr -d '\r' < "$KEY_FILE" > "${KEY_FILE}.tmp"
mv "${KEY_FILE}.tmp" "$KEY_FILE"
if [ ! -s "$KEY_FILE" ]; then
echo "SSH key file is empty after writing secret"
exit 1
fi
KEY_HEADER="$(head -n1 "$KEY_FILE" || true)"
case "$KEY_HEADER" in
"-----BEGIN OPENSSH PRIVATE KEY-----"|"-----BEGIN RSA PRIVATE KEY-----"|"-----BEGIN EC PRIVATE KEY-----"|"-----BEGIN DSA PRIVATE KEY-----"|"-----BEGIN PRIVATE KEY-----")
;;
*)
echo "AUR_SSH_PRIVATE_KEY has an invalid private key header: $KEY_HEADER"
exit 1
;;
esac
if ! ssh-keygen -y -f "$KEY_FILE" > ~/.ssh/curd_aur_deploy.pub 2>/dev/null; then
echo "AUR_SSH_PRIVATE_KEY is not a valid, unencrypted SSH private key"
exit 1
fi
chmod 600 "$KEY_FILE"
chmod 644 ~/.ssh/curd_aur_deploy.pub
ssh-keyscan -H aur.archlinux.org >> ~/.ssh/known_hosts
chmod 644 ~/.ssh/known_hosts
echo "Validated deploy key format. Add the matching public key to the AUR account SSH keys."
- name: Clone AUR repository
env:
GIT_SSH_COMMAND: ssh -i ~/.ssh/curd_aur_deploy -o IdentitiesOnly=yes
run: |
set -euo pipefail
git clone --depth 1 ssh://aur@aur.archlinux.org/curd.git aur-curd
- name: Update AUR package files
working-directory: aur-curd
run: |
set -euo pipefail
{
printf '%s\n' '# Maintainer: Wraient <rushikeshwastaken@gmail.com>'
printf '%s\n' "pkgname='curd'"
printf '%s\n' "pkgver=${{ steps.release.outputs.version }}"
printf '%s\n' 'pkgrel=1'
printf '%s\n' 'pkgdesc="Watch anime in CLI with AniList Tracking, Discord RPC, Intro/Outro/Filler/Recap Skipping, etc."'
printf '%s\n' "arch=('x86_64')"
printf '%s\n' 'url="https://github.com/Wraient/curd"'
printf '%s\n' "license=('GPL')"
printf '%s\n' "depends=('mpv' 'rofi' 'ueberzugpp')"
printf '%s\n' "provides=('curd')"
printf '%s\n' "conflicts=('curd')"
printf '%s\n' 'source=("https://github.com/Wraient/curd/releases/download/v${pkgver}/curd-linux-x86_64")'
printf '%s\n' "sha256sums=('${{ steps.release.outputs.sha256 }}')"
printf '\n'
printf '%s\n' 'package() {'
printf '%s\n' ' install -Dm755 "$srcdir/curd-linux-x86_64" "$pkgdir/usr/bin/curd"'
printf '%s\n' '}'
} > PKGBUILD
# Fail fast if checksum/source/install-target drift.
grep -q '^source=(' PKGBUILD
grep -q '^sha256sums=(' PKGBUILD
grep -q 'curd-linux-x86_64' PKGBUILD
grep -q 'install -Dm755 "\$srcdir/curd-linux-x86_64" "\$pkgdir/usr/bin/curd"' PKGBUILD
bash -n PKGBUILD
set +u
# shellcheck disable=SC1091
source PKGBUILD
set -u
pkgbase_value="${pkgbase:-}"
if [ -z "${pkgbase_value}" ]; then
pkgbase_value="${pkgname[0]:-${pkgname:-}}"
fi
{
printf 'pkgbase = %s\n' "$pkgbase_value"
[ -n "${pkgdesc:-}" ] && printf '\tpkgdesc = %s\n' "$pkgdesc"
[ -n "${pkgver:-}" ] && printf '\tpkgver = %s\n' "$pkgver"
[ -n "${pkgrel:-}" ] && printf '\tpkgrel = %s\n' "$pkgrel"
[ -n "${epoch:-}" ] && printf '\tepoch = %s\n' "$epoch"
[ -n "${url:-}" ] && printf '\turl = %s\n' "$url"
for item in "${arch[@]-}"; do [ -n "$item" ] && printf '\tarch = %s\n' "$item"; done
for item in "${license[@]-}"; do [ -n "$item" ] && printf '\tlicense = %s\n' "$item"; done
for item in "${makedepends[@]-}"; do [ -n "$item" ] && printf '\tmakedepends = %s\n' "$item"; done
for item in "${depends[@]-}"; do [ -n "$item" ] && printf '\tdepends = %s\n' "$item"; done
for item in "${checkdepends[@]-}"; do [ -n "$item" ] && printf '\tcheckdepends = %s\n' "$item"; done
for item in "${optdepends[@]-}"; do [ -n "$item" ] && printf '\toptdepends = %s\n' "$item"; done
for item in "${provides[@]-}"; do [ -n "$item" ] && printf '\tprovides = %s\n' "$item"; done
for item in "${conflicts[@]-}"; do [ -n "$item" ] && printf '\tconflicts = %s\n' "$item"; done
for item in "${replaces[@]-}"; do [ -n "$item" ] && printf '\treplaces = %s\n' "$item"; done
for item in "${source[@]-}"; do [ -n "$item" ] && printf '\tsource = %s\n' "$item"; done
for item in "${md5sums[@]-}"; do [ -n "$item" ] && printf '\tmd5sums = %s\n' "$item"; done
for item in "${sha1sums[@]-}"; do [ -n "$item" ] && printf '\tsha1sums = %s\n' "$item"; done
for item in "${sha224sums[@]-}"; do [ -n "$item" ] && printf '\tsha224sums = %s\n' "$item"; done
for item in "${sha256sums[@]-}"; do [ -n "$item" ] && printf '\tsha256sums = %s\n' "$item"; done
for item in "${sha384sums[@]-}"; do [ -n "$item" ] && printf '\tsha384sums = %s\n' "$item"; done
for item in "${sha512sums[@]-}"; do [ -n "$item" ] && printf '\tsha512sums = %s\n' "$item"; done
for item in "${b2sums[@]-}"; do [ -n "$item" ] && printf '\tb2sums = %s\n' "$item"; done
printf '\n'
for pkg in "${pkgname[@]-}"; do [ -n "$pkg" ] && printf 'pkgname = %s\n' "$pkg"; done
} > .SRCINFO
grep -Fq "pkgver = ${{ steps.release.outputs.version }}" .SRCINFO
grep -Fq "sha256sums = ${{ steps.release.outputs.sha256 }}" .SRCINFO
- name: Commit and push to AUR
working-directory: aur-curd
env:
GIT_SSH_COMMAND: ssh -i ~/.ssh/curd_aur_deploy -o IdentitiesOnly=yes
run: |
set -euo pipefail
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
if git diff --quiet; then
echo "No changes to commit"
exit 0
fi
git add PKGBUILD .SRCINFO
git commit -m "Update to version ${{ steps.release.outputs.version }}"
git push origin HEAD:master
- name: Cleanup
if: always()
run: |
rm -f ~/.ssh/curd_aur_deploy
rm -f ~/.ssh/curd_aur_deploy.pub
================================================
FILE: Build/buildlinux
================================================
#!/bin/bash
./Build/buildlinux-arm64
./Build/buildlinux-x86_64
================================================
FILE: Build/buildlinux-arm64
================================================
VERSION=$(cat VERSION.txt)
CGO_ENABLED=0 GOOS=linux GOARCH=arm64 go build -o curd-linux-arm64 -ldflags="-X main.version=${VERSION} -s -w" -trimpath cmd/curd/main.go
if [[ "$GITHUB_EVENT_NAME" == "push" && "$GITHUB_REF" == "refs/heads/main" && "$GITHUB_EVENT_HEAD_COMMIT_MESSAGE" == *"release:"* ]] || [[ "$COMPRESS" == "true" ]]; then
upx --best --ultra-brute curd-linux-arm64
fi
================================================
FILE: Build/buildlinux-x86_64
================================================
VERSION=$(cat VERSION.txt)
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o curd-linux-x86_64 -ldflags="-X main.version=${VERSION} -s -w" -trimpath cmd/curd/main.go
if [[ "$GITHUB_EVENT_NAME" == "push" && "$GITHUB_REF" == "refs/heads/main" && "$GITHUB_EVENT_HEAD_COMMIT_MESSAGE" == *"release:"* ]] || [[ "$COMPRESS" == "true" ]]; then
upx --best --ultra-brute curd-linux-x86_64
fi
================================================
FILE: Build/buildmac
================================================
#!/bin/bash
./Build/buildmac-arm64
./Build/buildmac-x86_64
================================================
FILE: Build/buildmac-arm64
================================================
VERSION=$(cat VERSION.txt)
CGO_ENABLED=0 GOOS=darwin GOARCH=arm64 go build -o curd-macos-arm64 -ldflags="-X main.version=${VERSION}" cmd/curd/main.go
================================================
FILE: Build/buildmac-x86_64
================================================
VERSION=$(cat VERSION.txt)
CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 go build -o curd-macos-x86_64 -ldflags="-X main.version=${VERSION}" -trimpath cmd/curd/main.go
================================================
FILE: Build/buildwindows
================================================
#!/bin/bash
# Set required Windows build environment variables
export CGO_ENABLED=1
export GOOS=windows
# Build for ARM64 (Broken due to npipe and rich-go)
# export GOARCH=arm64
# CC=x86_64-w64-mingw32-gcc ./Build/buildwindows-arm64
# Build for x86_64
export GOARCH=amd64
CC=x86_64-w64-mingw32-gcc ./Build/buildwindows-x86_64
================================================
FILE: Build/buildwindows-arm64
================================================
VERSION=$(cat VERSION.txt)
CGO_ENABLED=0 GOOS=windows GOARCH=arm64 go build -o curd-windows-arm64.exe -ldflags="-X main.version=${VERSION}" cmd/curd/main.go
if [[ "$GITHUB_EVENT_NAME" == "push" && "$GITHUB_REF" == "refs/heads/main" && "$GITHUB_EVENT_HEAD_COMMIT_MESSAGE" == *"release:"* ]] || [[ "$COMPRESS" == "true" ]]; then
upx --best --ultra-brute curd-windows-arm64.exe
fi
================================================
FILE: Build/buildwindows-x86_64
================================================
VERSION=$(cat VERSION.txt)
CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build -o curd-windows-x86_64.exe -ldflags="-X main.version=${VERSION}" cmd/curd/main.go
if [[ "$GITHUB_EVENT_NAME" == "push" && "$GITHUB_REF" == "refs/heads/main" && "$GITHUB_EVENT_HEAD_COMMIT_MESSAGE" == *"release:"* ]] || [[ "$COMPRESS" == "true" ]]; then
upx --best --ultra-brute curd-windows-x86_64.exe
fi
================================================
FILE: Build/curd-windows-build.iss
================================================
[Setup]
AppName=Curd Installer
AppVersion=1.4.0
DefaultDirName={userappdata}\Curd
PrivilegesRequired=lowest
AllowNoIcons=yes
OutputBaseFilename=curd-windows-installer
UsePreviousAppDir=yes
Compression=lzma2
SolidCompression=yes
[Tasks]
; Define a task for creating a desktop shortcut
Name: "desktopicon"; Description: "Create a &desktop shortcut"; GroupDescription: "Additional Options";
[Files]
; Copy the Curd executable to the install directory
Source: "..\releases\curd-{#SetupSetting("AppVersion")}\windows\curd-windows-x86_64.exe"; DestDir: "{app}"; DestName: "curd.exe"; Flags: ignoreversion
Source: "mpv\mpv.exe"; DestDir: "{app}\bin"; Flags: ignoreversion
[Icons]
; Create the application icon in the Start Menu
Name: "{group}\Curd"; Filename: "{app}\curd.exe"
; Create a desktop shortcut if the user checked the option
Name: "{userdesktop}\Curd"; Filename: "{app}\curd.exe"; Tasks: desktopicon
================================================
FILE: Build/release
================================================
#!/bin/bash
# Ask for version number
read -p "Enter the version number: " version
release_folder="releases/curd-$version"
windows_folder="$release_folder/windows"
linux_folder="$release_folder/linux"
macos_folder="$release_folder/macos"
installer_script="Build/curd-windows-build.iss"
# Ensure required directories exist
mkdir -p "$windows_folder" "$linux_folder" "$macos_folder"
# Build Linux binary
echo "Building Linux binary..."
bash Build/buildlinux
# Move the Linux binary to the release folder
if [ -f "curd-linux-x86_64" ]; then
mv curd-linux-x86_64 "$linux_folder"
else
echo "Linux build failed. Please check Build/buildlinux."
exit 1
fi
if [ -f "curd-linux-arm64" ]; then
mv curd-linux-arm64 "$linux_folder"
else
echo "Linux build failed. Please check Build/buildlinux-arm64."
exit 1
fi
# Build macOS binaries
echo "Building macOS binaries..."
bash Build/buildmac
if [ -f "curd-macos-x86_64" ]; then
mv curd-macos-x86_64 "$macos_folder"
else
echo "macOS x86-64 build failed. Please check Build/buildmac-x86_64."
exit 1
fi
if [ -f "curd-macos-arm64" ]; then
mv curd-macos-arm64 "$macos_folder"
else
echo "macOS arm64 build failed. Please check Build/buildmac-arm64."
exit 1
fi
# Create Universal binary for macOS
echo "Creating macOS Universal binary..."
llvm-lipo -create "$macos_folder/curd-macos-x86_64" "$macos_folder/curd-macos-arm64" -output "$macos_folder/curd-macos-universal"
# rm "$macos_folder/curd-macos-x86_64" "$macos_folder/curd-macos-arm64"
if [ ! -f "$macos_folder/curd-macos-universal" ]; then
echo "macOS arm64 build failed. Please check Build/buildmac."
exit 1
fi
# Update version in the installer script
sed -i "s/^AppVersion=.*/AppVersion=$version/" "$installer_script"
# Build Windows binary
echo "Building Windows binary..."
bash Build/buildwindows
# Uncompress mpv.exe.gz
echo "Uncompressing mpv.exe..."
mkdir -p "Build/mpv"
gunzip -c Build/mpv.exe.gz > "Build/mpv/mpv.exe"
# Move the Windows binary to the release folder
if [ -f "curd-windows-x86_64.exe" ]; then
mv curd-windows-x86_64.exe "$windows_folder"
else
echo "Windows build failed. Please check Build/buildwindows-x86_64."
exit 1
fi
# NOTE: Broken due to npipe and rich-go
# if [ -f "curd-windows-arm64.exe" ]; then
# mv curd-windows-arm64.exe "$windows_folder"
# else
# echo "Windows build failed. Please check Build/buildwindows-arm64."
# exit 1
# fi
# Create Windows installer with Inno Setup
echo "Creating Windows installer..."
wine "C:\Program Files (x86)\Inno Setup 6\ISCC.exe" "$installer_script"
# Move installer to the release folder
installer_output="Build/Output/curd-windows-installer.exe"
if [ -f "$installer_output" ]; then
mv "$installer_output" "$windows_folder"
else
echo "Installer creation failed. Please check Inno Setup script output."
fi
rm "Build/mpv/mpv.exe"
echo "Release build completed in $release_folder."
================================================
FILE: Build/requirements.txt
================================================
mingw-w64-gcc # Build arm64 windows binary
llvm-lipo # Build universal macos binary
================================================
FILE: LICENSE
================================================
GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The GNU General Public License is a free, copyleft license for
software and other kinds of works.
The licenses for most software and other practical works are designed
to take away your freedom to share and change the works. By contrast,
the GNU General Public License is intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users. We, the Free Software Foundation, use the
GNU General Public License for most of our software; it applies also to
any other work released this way by its authors. You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.
To protect your rights, we need to prevent others from denying you
these rights or asking you to surrender the rights. Therefore, you have
certain responsibilities if you distribute copies of the software, or if
you modify it: responsibilities to respect the freedom of others.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must pass on to the recipients the same
freedoms that you received. You must make sure that they, too, receive
or can get the source code. And you must show them these terms so they
know their rights.
Developers that use the GNU GPL protect your rights with two steps:
(1) assert copyright on the software, and (2) offer you this License
giving you legal permission to copy, distribute and/or modify it.
For the developers' and authors' protection, the GPL clearly explains
that there is no warranty for this free software. For both users' and
authors' sake, the GPL requires that modified versions be marked as
changed, so that their problems will not be attributed erroneously to
authors of previous versions.
Some devices are designed to deny users access to install or run
modified versions of the software inside them, although the manufacturer
can do so. This is fundamentally incompatible with the aim of
protecting users' freedom to change the software. The systematic
pattern of such abuse occurs in the area of products for individuals to
use, which is precisely where it is most unacceptable. Therefore, we
have designed this version of the GPL to prohibit the practice for those
products. If such problems arise substantially in other domains, we
stand ready to extend this provision to those domains in future versions
of the GPL, as needed to protect the freedom of users.
Finally, every program is threatened constantly by software patents.
States should not allow patents to restrict development and use of
software on general-purpose computers, but in those that do, we wish to
avoid the special danger that patents applied to a free program could
make it effectively proprietary. To prevent this, the GPL assures that
patents cannot be used to render the program non-free.
The precise terms and conditions for copying, distribution and
modification follow.
TERMS AND CONDITIONS
0. Definitions.
"This License" refers to version 3 of the GNU General Public License.
"Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.
"The Program" refers to any copyrightable work licensed under this
License. Each licensee is addressed as "you". "Licensees" and
"recipients" may be individuals or organizations.
To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy. The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.
A "covered work" means either the unmodified Program or a work based
on the Program.
To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy. Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.
To "convey" a work means any kind of propagation that enables other
parties to make or receive copies. Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.
An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License. If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.
1. Source Code.
The "source code" for a work means the preferred form of the work
for making modifications to it. "Object code" means any non-source
form of a work.
A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.
The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form. A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.
The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities. However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work. For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.
The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.
The Corresponding Source for a work in source code form is that
same work.
2. Basic Permissions.
All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met. This License explicitly affirms your unlimited
permission to run the unmodified Program. The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work. This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.
You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force. You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright. Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.
Conveying under any other circumstances is permitted solely under
the conditions stated below. Sublicensing is not allowed; section 10
makes it unnecessary.
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.
When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.
4. Conveying Verbatim Copies.
You may convey verbatim copies of the Program's source code as you
receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.
You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.
5. Conveying Modified Source Versions.
You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:
a) The work must carry prominent notices stating that you modified
it, and giving a relevant date.
b) The work must carry prominent notices stating that it is
released under this License and any conditions added under section
7. This requirement modifies the requirement in section 4 to
"keep intact all notices".
c) You must license the entire work, as a whole, under this
License to anyone who comes into possession of a copy. This
License will therefore apply, along with any applicable section 7
additional terms, to the whole of the work, and all its parts,
regardless of how they are packaged. This License gives no
permission to license the work in any other way, but it does not
invalidate such permission if you have separately received it.
d) If the work has interactive user interfaces, each must display
Appropriate Legal Notices; however, if the Program has interactive
interfaces that do not display Appropriate Legal Notices, your
work need not make them do so.
A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit. Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.
6. Conveying Non-Source Forms.
You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:
a) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by the
Corresponding Source fixed on a durable physical medium
customarily used for software interchange.
b) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by a
written offer, valid for at least three years and valid for as
long as you offer spare parts or customer support for that product
model, to give anyone who possesses the object code either (1) a
copy of the Corresponding Source for all the software in the
product that is covered by this License, on a durable physical
medium customarily used for software interchange, for a price no
more than your reasonable cost of physically performing this
conveying of source, or (2) access to copy the
Corresponding Source from a network server at no charge.
c) Convey individual copies of the object code with a copy of the
written offer to provide the Corresponding Source. This
alternative is allowed only occasionally and noncommercially, and
only if you received the object code with such an offer, in accord
with subsection 6b.
d) Convey the object code by offering access from a designated
place (gratis or for a charge), and offer equivalent access to the
Corresponding Source in the same way through the same place at no
further charge. You need not require recipients to copy the
Corresponding Source along with the object code. If the place to
copy the object code is a network server, the Corresponding Source
may be on a different server (operated by you or a third party)
that supports equivalent copying facilities, provided you maintain
clear directions next to the object code saying where to find the
Corresponding Source. Regardless of what server hosts the
Corresponding Source, you remain obligated to ensure that it is
available for as long as needed to satisfy these requirements.
e) Convey the object code using peer-to-peer transmission, provided
you inform other peers where the object code and Corresponding
Source of the work are being offered to the general public at no
charge under subsection 6d.
A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.
A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling. In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage. For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product. A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.
"Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source. The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.
If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information. But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).
The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed. Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.
Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.
7. Additional Terms.
"Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law. If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.
When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it. (Additional permissions may be written to require their own
removal in certain cases when you modify the work.) You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.
Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:
a) Disclaiming warranty or limiting liability differently from the
terms of sections 15 and 16 of this License; or
b) Requiring preservation of specified reasonable legal notices or
author attributions in that material or in the Appropriate Legal
Notices displayed by works containing it; or
c) Prohibiting misrepresentation of the origin of that material, or
requiring that modified versions of such material be marked in
reasonable ways as different from the original version; or
d) Limiting the use for publicity purposes of names of licensors or
authors of the material; or
e) Declining to grant rights under trademark law for use of some
trade names, trademarks, or service marks; or
f) Requiring indemnification of licensors and authors of that
material by anyone who conveys the material (or modified versions of
it) with contractual assumptions of liability to the recipient, for
any liability that these contractual assumptions directly impose on
those licensors and authors.
All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10. If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term. If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.
If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.
Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.
8. Termination.
You may not propagate or modify a covered work except as expressly
provided under this License. Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).
However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.
Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.
Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License. If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.
9. Acceptance Not Required for Having Copies.
You are not required to accept this License in order to receive or
run a copy of the Program. Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance. However,
nothing other than this License grants you permission to propagate or
modify any covered work. These actions infringe copyright if you do
not accept this License. Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.
10. Automatic Licensing of Downstream Recipients.
Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License. You are not responsible
for enforcing compliance by third parties with this License.
An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations. If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.
You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License. For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.
11. Patents.
A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based. The
work thus licensed is called the contributor's "contributor version".
A contributor's "essential patent claims" are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version. For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.
Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.
In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement). To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.
If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients. "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.
If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.
A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License. You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.
Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.
12. No Surrender of Others' Freedom.
If conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all. For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.
13. Use with the GNU Affero General Public License.
Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU Affero General Public License into a single
combined work, and to convey the resulting work. The terms of this
License will continue to apply to the part which is the covered work,
but the special requirements of the GNU Affero General Public License,
section 13, concerning interaction through a network will apply to the
combination as such.
14. Revised Versions of this License.
The Free Software Foundation may publish revised and/or new versions of
the GNU General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the
Program specifies that a certain numbered version of the GNU General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation. If the Program does not specify a version number of the
GNU General Public License, you may choose any version ever published
by the Free Software Foundation.
If the Program specifies that a proxy can decide which future
versions of the GNU General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.
Later license versions may give you additional or different
permissions. However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.
15. Disclaimer of Warranty.
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. Limitation of Liability.
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.
17. Interpretation of Sections 15 and 16.
If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
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 <https://www.gnu.org/licenses/>.
Also add information on how to contact you by electronic and paper mail.
If the program does terminal interaction, make it output a short
notice like this when it starts in an interactive mode:
<program> Copyright (C) <year> <name of author>
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, your program's commands
might be different; for a GUI interface, you would use an "about box".
You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU GPL, see
<https://www.gnu.org/licenses/>.
The GNU General Public License does not permit incorporating your program
into proprietary programs. If your program is a subroutine library, you
may consider it more useful to permit linking proprietary applications with
the library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License. But first, please read
<https://www.gnu.org/licenses/why-not-lgpl.html>.
================================================
FILE: PKGBUILD
================================================
# Maintainer: Wraient <rushikeshwastaken@gmail.com>
pkgname='curd'
pkgver=1.1.4
pkgrel=1
pkgdesc="Watch anime in CLI with AniList Tracking, Discord RPC, Intro/Outro/Filler/Recap Skipping, etc."
arch=('x86_64')
url="https://github.com/Wraient/curd"
license=('GPL')
depends=('mpv' 'rofi' 'ueberzugpp')
provides=('curd')
conflicts=('curd')
source=("https://github.com/Wraient/curd/releases/download/v${pkgver}/curd-linux-x86_64")
sha256sums=('SKIP')
package() {
install -Dm755 "$srcdir/curd-linux-x86_64" "$pkgdir/usr/bin/curd"
}
================================================
FILE: README.md
================================================
# Curd
A cli application to stream anime with [Anilist](https://anilist.co/) integration and Discord RPC written in golang.
Works on Linux, MacOS and Windows.
## Join the discord server
https://discord.gg/rrpBfu2gHq
## Join the Matrix server
https://matrix.to/#/#curd:matrix.org
## Demo Video
Normal mode:
https://github.com/user-attachments/assets/376e7580-b1af-40ee-82c3-154191f75b79
Rofi with Image preview
https://github.com/user-attachments/assets/cbf799bc-9fdd-4402-ab61-b4e31f1e264d
## Features
- Multiple Content Providers (AllAnime and Animepahe) with up to 1080p support
- Built-in headless browser to bypass Cloudflare/DDoS-Guard protections
- Stream anime online
- Update anime in Anilist after completion
- Skip anime Intro and Outro
- Skip Filler and Recap episodes
- Discord RPC about the anime
- Rofi support
- Image preview in rofi
- Local anime history to continue from where you left off last time
- Save mpv speed for next episode
- Configurable through config file
## Installing and Setup
> **Note**: `Curd` requires `mpv`, `rofi`, and `ueberzugpp` for Rofi support and image preview. These are included in the installation instructions below for each distribution.
### Linux
<details>
<summary>Arch Linux / Manjaro (AUR-based systems)</summary>
Using Yay:
```bash
yay -Sy curd
```
or using Paru:
```bash
paru -Sy curd
```
Or, to manually clone and install:
```bash
git clone https://aur.archlinux.org/curd.git
cd curd
makepkg -si
sudo pacman -S rofi ueberzugpp
```
</details>
<details>
<summary>Debian / Ubuntu (and derivatives)</summary>
```bash
sudo apt update
sudo apt install mpv curl rofi ueberzugpp
# For x86_64 systems:
curl -Lo curd https://github.com/Wraient/curd/releases/latest/download/curd-linux-x86_64
# For ARM64 systems:
curl -Lo curd https://github.com/Wraient/curd/releases/latest/download/curd-linux-arm64
chmod +x curd
sudo mv curd /usr/bin/
curd
```
</details>
<details>
<summary>Fedora Installation</summary>
```bash
sudo dnf update
sudo dnf install mpv curl rofi ueberzugpp
# For x86_64 systems:
curl -Lo curd https://github.com/Wraient/curd/releases/latest/download/curd-linux-x86_64
# For ARM64 systems:
curl -Lo curd https://github.com/Wraient/curd/releases/latest/download/curd-linux-arm64
chmod +x curd
sudo mv curd /usr/bin/
curd
```
</details>
<details>
<summary>openSUSE Installation</summary>
```bash
sudo zypper refresh
sudo zypper install mpv curl rofi ueberzugpp
# For x86_64 systems:
curl -Lo curd https://github.com/Wraient/curd/releases/latest/download/curd-linux-x86_64
# For ARM64 systems:
curl -Lo curd https://github.com/Wraient/curd/releases/latest/download/curd-linux-arm64
chmod +x curd
sudo mv curd /usr/bin/
curd
```
</details>
<details>
<summary>NixOS Installation</summary>
1. Add curd as a flake input, for example:
```nix
{
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
curd = {
url = "github:Wraient/curd";
inputs.nixpkgs.follows = "nixpkgs";
};
}
}
```
2. Install the package, for example:
```nix
{inputs, pkgs, ...}: {
environment.systemPackages = [
inputs.curd.packages.${pkgs.system}.default
];
}
```
</details>
<details>
<summary>Generic Installation</summary>
Choose the appropriate binary for your system:
```bash
# For Linux x86_64:
curl -Lo curd https://github.com/Wraient/curd/releases/latest/download/curd-linux-x86_64
# For Linux ARM64:
curl -Lo curd https://github.com/Wraient/curd/releases/latest/download/curd-linux-arm64
chmod +x curd
sudo mv curd /usr/bin/
curd
```
</details>
<details>
<summary>Uninstallation</summary>
```bash
sudo rm /usr/bin/curd
```
For AUR-based distributions:
```bash
yay -R curd
```
</details>
### MacOS
<details>
<summary>MacOS Installation</summary>
Install required dependencies
```bash
brew install mpv curl
```
Download the appropriate binary for your system:
- For Apple Silicon (M1/M2) Macs:
```bash
curl -Lo curd https://github.com/Wraient/curd/releases/latest/download/curd-macos-arm64
```
- For Intel Macs:
```bash
curl -Lo curd https://github.com/Wraient/curd/releases/latest/download/curd-macos-x86_64
```
- For Universal Binary (works on both architectures):
```bash
curl -Lo curd https://github.com/Wraient/curd/releases/latest/download/curd-macos-universal
```
Then complete the installation:
```bash
chmod +x curd
sudo mv curd /usr/local/bin/
curd
```
</details>
<details>
<summary>Uninstallation</summary>
```bash
sudo rm /usr/local/bin/curd
```
</details>
### Windows
<details>
<summary>Windows Installation</summary>
Option 1: Using the installer
- Download and run the [Windows Installer](https://github.com/Wraient/curd/releases/latest/download/curd-windows-installer.exe)
Option 2: Standalone executable
- Download [curd-windows-x86_64.exe](https://github.com/Wraient/curd/releases/latest/download/curd-windows-x86_64.exe)
</details>
## Data Storage
<details>
<summary>Windows</summary>
Stroage: (Token, Timestamps, debug.log, etc)
```bash
C:\.local\share\curd
```
Config :
```bash
C:\Users\USERNAME\AppData\Roaming\Curd
```
</details>
<details>
<summary>Linux/Unix</summary>
Stroage: (Token, Timestamps, debug.log, etc)
```bash
$USER/.local/share/curd
```
Config :
```bash
$USER/.config/curd
```
</details>
## Usage
Run `curd` with the following options:
```bash
curd [options]
```
### Arguments would always take precedence over configuration
> **Note**:
> - To use rofi you need rofi and ueberzug installed.
> - Rofi .rasi files are at default `~/.local/share/curd/`
> - You can edit them as you like.
> - If there are no rasi files with specific names, they would be downloaded from this repo.
### Options
| Flag | Description | Default |
|---------------------------|-------------------------------------------------------------------------|---------------|
| `-c` | Continue the last episode | - |
| `-change-token` | Change your authentication token | - |
| `-dub` | Watch the dubbed version of the anime | - |
| `-sub` | Watch the subbed version of the anime | - |
| `-new` | Add a new anime to your list | - |
| `-e` | Edit the configuration file | - |
| `-skip-op` | Automatically skip the opening section of each episode | `true` |
| `-skip-ed` | Automatically skip the ending section of each episode | `true` |
| `-skip-filler` | Automatically skip filler episodes | `true` |
| `-skip-recap` | Automatically skip recap sections | `true` |
| `-discord-presence` | Enable or disable Discord presence | `true` |
| `-image-preview` | Show an image preview of the anime | - |
| `-no-image-preview` | Disable image preview | - |
| `-next-episode-prompt` | Prompt for the next episode after completing one | - |
| `-rofi` | Open anime selection in the rofi interface | - |
| `-no-rofi` | Disable rofi interface | - |
| `-percentage-to-mark-complete` | Set the percentage watched to mark an episode as complete | `85` |
| `-player` | Specify the player to use for playback | `"mpv"` |
| `-save-mpv-speed` | Save the current MPV speed setting for future sessions | `true` |
| `-score-on-completion` | Prompt to score the episode on completion | `true` |
| `-storage-path` | Path to the storage directory | `"$HOME/.local/share/curd"` |
| `-subs-lang` | Set the language for subtitles | `"english"` |
| `-u` | Update the script | - |
| `-v` | Show curd version | - |
### Examples
- **Continue the Last Episode**:
```bash
curd -c
```
- **Add a New Anime**:
```bash
curd -percentage-to-mark-complete=90
```
- **Play with Rofi and Image Preview**:
```bash
curd -rofi -image-preview
```
## Configuration
All configurations are stored in a file you can edit with the `-e` option.
```bash
curd -e
```
Script is made in a way that you use it for one session of watching.
You can quit it anytime and the resume time would be saved in the history file
more settings can be found at config file.
config file is located at ```~/.config/curd/curd.conf```
| **Option** | **Type** | **Valid Values** | **Description** |
|---------------------------|------------|-------------------------------------------|---------------------------------------------------------------------------------------------------|
| `DiscordPresence` | Boolean | `true`, `false` | Enables or disables Discord Rich Presence integration. |
| `AnimeNameLanguage` | Enum | `english`, `romaji` | Sets the preferred language for anime names. |
| `MpvArgs` | List | all mpv args eg ["--fullscreen=yes", "--mute=yes"] | Add args to mpv player |
| `AddMissingOptions` | Boolean | `true`, `false` | Automatically adds missing configuration options with default values to the config file. |
| `AlternateScreen` | Boolean | `true`, `false` | Toggles the use of an alternate screen buffer for cleaner UI. |
| `RofiSelection` | Boolean | `true`, `false` | Enables or disables anime selection via Rofi. |
| `PercentageToMarkComplete`| Integer | `0` to `100` | Sets the percentage of an episode watched to consider it as completed. |
| `StoragePath` | String | Any valid path (Environment variables accepted) | Specifies the directory where Curd stores its data. |
| `SubOrDub` | Enum | `sub`, `dub` | Sets the preferred format for anime audio. |
| `NextEpisodePrompt` | Boolean | `true`, `false` | Prompts the user before automatically playing the next episode. |
| `SubsLanguage` | String | `english` (redundant rn) | Sets the preferred subtitle language. |
| `ScoreOnCompletion` | Boolean | `true`, `false` | Automatically prompts the user to rate the anime upon completion. |
| `SkipOp` | Boolean | `true`, `false` | Automatically skips the opening of episodes when supported. |
| `SkipEd` | Boolean | `true`, `false` | Automatically skips the ending of episodes when supported. |
| `SkipRecap` | Boolean | `true`, `false` | Skips recap sections in episodes when supported. |
| `ImagePreview` | Boolean | `true`, `false` | Enables or disables image previews during anime selection (only for rofi). |
| `Player` | String | any mpv-compatible binary (e.g. `mpv`, `iina`) | Player binary used for playback. If not found, Curd falls back to `mpv`. |
| `SaveMpvSpeed` | Boolean | `true`, `false` | Retains the playback speed set in MPV for next episode. |
| `SkipFiller` | Boolean | `true`, `false` | Skips filler episodes when supported. |
| `MenuOrder` | String | Comma-separated list | Controls which menu items appear and their order. Available options: `CURRENT`, `ALL`, `UNTRACKED`, `UPDATE`, `CONTINUE_LAST`, `PLANNING`, `COMPLETED`, `PAUSED`, `DROPPED`, `REWATCHING`, `PROVIDER`. Only listed items will be shown. Default: `CURRENT,ALL,UNTRACKED,UPDATE,CONTINUE_LAST,PROVIDER` |
| `Provider` | Enum | `allanime`, `animepahe` | Sets the content provider for anime streams. `animepahe` requires chromium to bypass DDoS-Guard. Default: `allanime` |
## Todo (fix)
- Use Powershell for windows token input instead of notepad or cmd
- Add a better way to do commands in windows (Convinience for users)
## Dependencies
- mpv - Video player (required fallback)
- iina - Optional mpv-based player on macOS
- rofi - Selection menu
- ueberzug - Display images in rofi
- chromium - Required for Animepahe (auto-downloaded by default, but Termux users must install manually via `pkg install chromium`)
## API Used
- [Anilist API](https://anilist.gitbook.io/anilist-apiv2-docs) - Update user data and download user data
- [AniSkip API](https://api.aniskip.com/api-docs) - Get anime intro and outro timings
- [AllAnime Content](https://allanime.to/) - Fetch anime url
- [Animepahe Content](https://animepahe.pw/) - Alternative provider for 1080p streams
- [Jikan](https://jikan.moe/) - Get filler episode number
## Credits
- [ani-cli](https://github.com/pystardust/ani-cli) - Code for fetching anime url
- [jerry](https://github.com/justchokingaround/jerry) - For the inspiration
================================================
FILE: VERSION.txt
================================================
1.4.0
================================================
FILE: cmd/curd/main.go
================================================
package main
import (
"flag"
"fmt"
"os"
"path/filepath"
"runtime"
"strconv"
"sync"
"time"
"github.com/wraient/curd/internal"
)
var version string // Will be set by ldflags during build
func resolvedVersion() string {
if version == "" {
return "1.4.0"
}
return version
}
func main() {
var anime internal.Anime
var user internal.User
internal.SetGlobalAnime(&anime)
configDir, err := os.UserConfigDir()
if err != nil {
// Fallback if UserConfigDir fails
if runtime.GOOS == "windows" {
configDir = filepath.Join(os.Getenv("USERPROFILE"), "AppData", "Roaming")
} else {
configDir = filepath.Join(os.Getenv("HOME"), ".config")
}
}
configFilePath := filepath.Join(configDir, "curd", "curd.conf")
// load curd userCurdConfig
userCurdConfig, err := internal.LoadConfig(configFilePath)
if err != nil {
fmt.Println("Error loading config:", err)
return
}
internal.SetGlobalConfig(&userCurdConfig)
logFile := filepath.Join(os.ExpandEnv(userCurdConfig.StoragePath), "debug.log")
internal.SetGlobalLogFile(logFile)
internal.ClearLogFile(logFile)
// Flags configured here cause userconfig needs to be changed.
flag.StringVar(&userCurdConfig.Player, "player", userCurdConfig.Player, "Player binary for playback (mpv-compatible; falls back to mpv if unavailable)")
flag.StringVar(&userCurdConfig.StoragePath, "storage-path", userCurdConfig.StoragePath, "Path to the storage directory")
flag.StringVar(&userCurdConfig.SubsLanguage, "subs-lang", userCurdConfig.SubsLanguage, "Subtitles language")
flag.IntVar(&userCurdConfig.PercentageToMarkComplete, "percentage-to-mark-complete", userCurdConfig.PercentageToMarkComplete, "Percentage to mark episode as complete")
// Boolean flags that accept true/false
flag.BoolVar(&userCurdConfig.NextEpisodePrompt, "next-episode-prompt", userCurdConfig.NextEpisodePrompt, "Prompt for the next episode (true/false)")
flag.BoolVar(&userCurdConfig.SkipOp, "skip-op", userCurdConfig.SkipOp, "Skip opening (true/false)")
flag.BoolVar(&userCurdConfig.SkipEd, "skip-ed", userCurdConfig.SkipEd, "Skip ending (true/false)")
flag.BoolVar(&userCurdConfig.SkipFiller, "skip-filler", userCurdConfig.SkipFiller, "Skip filler episodes (true/false)")
flag.BoolVar(&userCurdConfig.SkipRecap, "skip-recap", userCurdConfig.SkipRecap, "Skip recap (true/false)")
flag.BoolVar(&userCurdConfig.ScoreOnCompletion, "score-on-completion", userCurdConfig.ScoreOnCompletion, "Score on episode completion (true/false)")
flag.BoolVar(&userCurdConfig.SaveMpvSpeed, "save-mpv-speed", userCurdConfig.SaveMpvSpeed, "Save MPV speed setting (true/false)")
flag.BoolVar(&userCurdConfig.DiscordPresence, "discord-presence", userCurdConfig.DiscordPresence, "Enable Discord presence (true/false)")
flag.StringVar(&userCurdConfig.DiscordClientId, "discord-client-id", userCurdConfig.DiscordClientId, "Discord client ID for Rich Presence")
continueLast := flag.Bool("c", false, "Continue last episode")
addNewAnime := flag.Bool("new", false, "Add new anime")
rofiSelection := flag.Bool("rofi", false, "Open selection in rofi")
noRofi := flag.Bool("no-rofi", false, "No rofi")
imagePreview := flag.Bool("image-preview", false, "Show image preview")
noImagePreview := flag.Bool("no-image-preview", false, "No image preview")
changeToken := flag.Bool("change-token", false, "Change token")
currentCategory := flag.Bool("current", false, "Current category")
updateScript := flag.Bool("u", false, "Update the script")
editConfig := flag.Bool("e", false, "Edit config")
subFlag := flag.Bool("sub", false, "Watch sub version")
dubFlag := flag.Bool("dub", false, "Watch dub version")
versionFlag := flag.Bool("v", false, "Print version information")
// Custom help/usage function
flag.Usage = func() {
internal.RestoreScreen()
fmt.Fprintf(os.Stderr, "Curd is a CLI tool to manage anime playback with advanced features like skipping intro, outro, filler, recap, tracking progress, and integrating with Discord.\n")
fmt.Fprintf(os.Stderr, "Usage of %s:\n", os.Args[0])
flag.PrintDefaults() // This prints the default flag information
}
flag.Parse()
// Validate PercentageToMarkComplete range (0-100) from CLI flag
if userCurdConfig.PercentageToMarkComplete < 0 {
userCurdConfig.PercentageToMarkComplete = 0
} else if userCurdConfig.PercentageToMarkComplete > 100 {
userCurdConfig.PercentageToMarkComplete = 100
}
// Check version before screen clearing
if *versionFlag {
fmt.Printf("Curd version: %s\n", resolvedVersion())
os.Exit(0)
}
anime.Ep.ContinueLast = *continueLast
if *updateScript {
repo := "wraient/curd"
fileName := "curd"
if err := internal.UpdateCurd(repo, fileName); err != nil {
internal.CurdOut(fmt.Sprintf("Error updating executable: %v\n", err))
internal.ExitCurd(err)
} else {
internal.CurdOut("Program Updated!")
internal.ExitCurd(nil)
}
}
if *changeToken {
internal.ChangeToken(&userCurdConfig, &user)
return
}
// Setup screen for interactive mode (only if not changing token)
internal.ClearScreen()
defer internal.RestoreScreen()
if *currentCategory {
userCurdConfig.CurrentCategory = true
}
if *rofiSelection {
userCurdConfig.RofiSelection = true
}
if *noRofi || runtime.GOOS == "windows" {
userCurdConfig.RofiSelection = false
}
if *imagePreview {
userCurdConfig.ImagePreview = true
}
if *noImagePreview || runtime.GOOS == "windows" {
userCurdConfig.ImagePreview = false
}
if *editConfig {
internal.EditConfig(configFilePath)
return
}
// Set SubOrDub based on the flags
if *subFlag {
userCurdConfig.SubOrDub = "sub"
} else if *dubFlag {
userCurdConfig.SubOrDub = "dub"
}
// Get the token from the token file
user.Token, err = internal.GetTokenFromFile(filepath.Join(os.ExpandEnv(userCurdConfig.StoragePath), "anilist_token.json"))
if err != nil {
internal.Log("Error reading token")
}
if user.Token == "" {
internal.ChangeToken(&userCurdConfig, &user)
}
if userCurdConfig.RofiSelection {
// Define a slice of file names to check and download
filesToCheck := []string{
"selectanimepreview.rasi",
"selectanime.rasi",
"userinput.rasi",
}
// Call the function to check and download files
err := internal.CheckAndDownloadFiles(os.ExpandEnv(userCurdConfig.StoragePath), filesToCheck)
if err != nil {
internal.Log(fmt.Sprintf("Error checking and downloading files: %v\n", err))
internal.CurdOut(fmt.Sprintf("Error checking and downloading files: %v\n", err))
internal.ExitCurd(err)
}
}
// Load animes in database
databaseFile := filepath.Join(os.ExpandEnv(userCurdConfig.StoragePath), "curd_history.txt")
databaseAnimes := internal.LocalGetAllAnime(databaseFile)
if *addNewAnime {
internal.AddNewAnime(&userCurdConfig, &anime, &user, &databaseAnimes)
// internal.ExitCurd(fmt.Errorf("Added new anime!"))
}
internal.SetupCurd(&userCurdConfig, &anime, &user, &databaseAnimes)
temp_anime, err := internal.FindAnimeByAnilistID(user.AnimeList, strconv.Itoa(anime.AnilistId))
if err != nil {
internal.Log("Error finding anime by Anilist ID: " + err.Error())
}
if anime.TotalEpisodes == temp_anime.Progress && temp_anime.Status != "CURRENT" {
internal.Log(temp_anime.Progress)
internal.Log(anime.TotalEpisodes)
internal.Log(user.AnimeList)
internal.Log("Rewatching anime: " + internal.GetAnimeName(anime))
anime.Rewatching = true
}
anime.Ep.Player.Speed = 1.0
// Get filler list concurrently
go func() {
// Get MAL ID first if not already set
if anime.MalId == 0 {
malID, err := internal.GetAnimeMalID(anime.AnilistId)
if err != nil {
internal.Log("Error getting MAL ID: " + err.Error())
return
}
anime.MalId = malID
}
fillerList, err := internal.FetchFillerEpisodes(anime.MalId)
if err != nil {
internal.Log("Error getting filler list: " + err.Error())
} else {
anime.FillerEpisodes = fillerList
internal.Log("Filler list fetched successfully")
// fmt.Println("Filler episodes: ", anime.FillerEpisodes)
}
}()
// Main loop (loop to keep starting new episodes)
for {
internal.Log(anime)
// Create a channel to signal when to exit the skip loop
var wg sync.WaitGroup
skipLoopDone := make(chan struct{})
skipLoopClosed := make(chan bool, 1) // Channel to track if skipLoopDone has been closed
skipLoopClosed <- false // Initialize to false (not closed yet)
// Get MalId and CoverImage (only if discord presence is enabled)
if userCurdConfig.DiscordPresence {
anime.MalId, anime.CoverImage, err = internal.GetAnimeIDAndImage(anime.AnilistId)
if err != nil {
internal.Log("Error getting anime ID and image: " + err.Error())
}
// Skip initial Discord presence - wait for MPV to provide real duration
// This avoids showing the default 25-minute duration before the video starts
internal.Log("Waiting for MPV to start to get actual video duration before showing Discord presence")
} else if anime.MalId == 0 {
anime.MalId, err = internal.GetAnimeMalID(anime.AnilistId)
if err != nil {
internal.Log("Error getting anime MAL ID: " + err.Error())
}
}
// Start curd (loop while episode is playing)
for {
// Check if current episode is filler/recap
err = internal.GetEpisodeData(anime.MalId, anime.Ep.Number, &anime)
if err != nil {
internal.Log("Error getting episode data, assuming non-filler: " + err.Error())
break // Break the loop and continue with playback
}
// Check if episode is filler
anime.Ep.IsFiller = internal.IsEpisodeFiller(anime.FillerEpisodes, anime.Ep.Number)
// If not filler/recap (or skip is disabled), break and continue with playback
if !((anime.Ep.IsFiller && userCurdConfig.SkipFiller) || (anime.Ep.IsRecap && userCurdConfig.SkipRecap)) {
if anime.Ep.LastWasSkipped {
go internal.UpdateAnimeProgress(user.Token, anime.AnilistId, anime.Ep.Number-1)
}
break
}
// If it is filler/recap, log it and move to next episode
if anime.Ep.IsFiller {
internal.CurdOut(fmt.Sprint("Filler episode, skipping: ", anime.Ep.Number))
// Get next canon episode
anime.Ep.Number = internal.GetNextCanonEpisode(anime.FillerEpisodes, anime.Ep.Number)
} else {
internal.CurdOut(fmt.Sprint("Recap episode, skipping: ", anime.Ep.Number))
anime.Ep.Number++
}
anime.Ep.LastWasSkipped = true
anime.Ep.Started = false
internal.LocalUpdateAnime(databaseFile, anime.AnilistId, anime.ProviderId, anime.Ep.Number, 0, 0, internal.GetAnimeName(anime), internal.GetProvider().Name())
// Check if we've reached the end of the series
if anime.Ep.Number > anime.TotalEpisodes {
internal.CurdOut("Reached end of series")
internal.ExitCurd(nil)
}
}
// Now start playback for the non-filler episode
anime.Ep.Player.SocketPath = internal.StartCurd(&userCurdConfig, &anime)
internal.Log(fmt.Sprint("Playback starting time: ", anime.Ep.Player.PlaybackTime))
internal.Log(anime.Ep.Player.SocketPath)
// Handle Android Intent external player
if anime.Ep.Player.SocketPath == "android-intent" {
internal.CurdOut(fmt.Sprintf("\nOpened external player for Episode %d.", anime.Ep.Number))
internal.CurdOut("Press Enter when you have finished watching...")
// Wait for user input to confirm completion
var input string
fmt.Scanln(&input)
// Mark as completed
anime.Ep.IsCompleted = true
// Update progress for the finished episode
// Local update
internal.LocalUpdateAnime(databaseFile, anime.AnilistId, anime.ProviderId, anime.Ep.Number, 0, 0, internal.GetAnimeName(anime), internal.GetProvider().Name())
// Check if we should continue to next episode
// On Android we always prompt because we don't know exactly when video ended
shouldContinue := internal.NextEpisodePromptCLI(&userCurdConfig)
if shouldContinue {
internal.StartNextEpisode(&anime, &userCurdConfig, databaseFile, user.Token)
continue
} else {
// Handle completion if this was the last episode
if anime.Ep.Number == anime.TotalEpisodes {
internal.HandleLastEpisodeCompletion(&userCurdConfig, &anime, user.Token)
}
// Update progress for the just finished episode (StartNextEpisode usually does this for previous ep, but here we exit)
if !anime.Rewatching {
internal.UpdateAnimeProgress(user.Token, anime.AnilistId, anime.Ep.Number)
}
internal.ExitCurd(nil)
}
}
wg.Add(1)
// Get episode data
go func() {
defer wg.Done()
err = internal.GetEpisodeData(anime.MalId, anime.Ep.Number, &anime)
if err != nil {
internal.Log("Error getting episode data: " + err.Error())
} else {
internal.Log(anime)
// if filler episode or recap episode and skip is enabled
if (anime.Ep.IsFiller && userCurdConfig.SkipFiller) || (anime.Ep.IsRecap && userCurdConfig.SkipRecap) {
if anime.Ep.IsFiller && userCurdConfig.SkipFiller {
internal.CurdOut(fmt.Sprint("Filler Episode, starting next episode: ", anime.Ep.Number+1))
internal.Log("Filler episode detected")
} else if anime.Ep.IsRecap && userCurdConfig.SkipRecap {
internal.CurdOut(fmt.Sprint("Recap Episode, starting next episode: ", anime.Ep.Number+1))
internal.Log("Recap episode detected")
}
anime.Ep.IsCompleted = true
if !userCurdConfig.NextEpisodePrompt {
// fmt.Println("[DEBUG] Starting next episode from filler/recap skip")
internal.StartNextEpisode(&anime, &userCurdConfig, databaseFile, user.Token)
} else {
// When NextEpisodePrompt is enabled, just call StartNextEpisode - it handles Rofi prompting internally
internal.ExitMPV(anime.Ep.Player.SocketPath)
internal.StartNextEpisode(&anime, &userCurdConfig, databaseFile, user.Token)
return
}
// Send command to close MPV
_, err := internal.MPVSendCommand(anime.Ep.Player.SocketPath, []interface{}{"quit"})
if err != nil {
internal.Log("Error closing MPV: " + err.Error())
}
// Exit the skip loop - only close if not already closed
select {
case isClosed := <-skipLoopClosed:
if !isClosed {
close(skipLoopDone)
skipLoopClosed <- true // Mark as closed
}
default:
// Channel is busy, another goroutine is handling closure
}
}
}
}()
wg.Add(1)
// Thread to update Discord presence with simple position-gap seek detection
go func() {
defer wg.Done()
if userCurdConfig.DiscordPresence {
var lastKnownPauseState bool = false
var lastKnownPosition int = 0
var lastStateCheck time.Time
var discordPresenceInitialized bool = false // Track if Discord presence has been set with real duration
for {
select {
case <-skipLoopDone:
return
default:
// Get current state from MPV
isPaused, err := internal.MPVSendCommand(anime.Ep.Player.SocketPath, []interface{}{"get_property", "pause"})
if err != nil {
internal.Log("Error getting pause status: " + err.Error())
time.Sleep(5 * time.Second)
continue
}
if isPaused == nil {
isPaused = true
}
// Get current time position
currentPos := 0
timePos, err := internal.MPVSendCommand(anime.Ep.Player.SocketPath, []interface{}{"get_property", "time-pos"})
if err == nil && timePos != nil {
if pos, ok := timePos.(float64); ok {
currentPos = int(pos + 0.5) // Round to nearest integer
}
}
currentPauseState := isPaused.(bool)
// Simple seek detection: position gap > 5 seconds
hasSeekEvent := false
if lastKnownPosition > 0 {
positionDiff := currentPos - lastKnownPosition
if positionDiff < -5 || positionDiff > 7 { // 5 sec backward or 7 sec forward (allowing normal playback + buffer)
hasSeekEvent = true
}
}
hasPlayPauseEvent := currentPauseState != lastKnownPauseState
// Determine if we should update Discord presence
shouldUpdate := false
// Force update every 30 seconds for Discord keep-alive
if lastStateCheck.IsZero() || time.Since(lastStateCheck) >= 30*time.Second {
shouldUpdate = true
}
// Update on pause state change
if hasPlayPauseEvent {
shouldUpdate = true
}
// Update on seek events
if hasSeekEvent {
shouldUpdate = true
}
if shouldUpdate {
// Only update Discord if we have real duration OR if presence was already initialized
totalDuration := anime.Ep.Duration
if totalDuration == 0 {
// Skip Discord updates until we have real duration from MPV
if !discordPresenceInitialized {
lastKnownPauseState = currentPauseState
lastKnownPosition = currentPos
lastStateCheck = time.Now()
time.Sleep(2 * time.Second)
continue
}
totalDuration = currentPos + 1 // Small duration to avoid divide by zero
} else {
discordPresenceInitialized = true // Mark as initialized once we have real duration
}
// Force update on seek events to bypass Discord's internal filtering
if hasSeekEvent {
err = internal.DiscordPresenceWithForce(anime, currentPauseState, currentPos, totalDuration, userCurdConfig.DiscordClientId, true)
} else {
err = internal.DiscordPresence(anime, currentPauseState, currentPos, totalDuration, userCurdConfig.DiscordClientId)
}
if err != nil {
internal.Log("Error setting Discord presence: " + err.Error())
}
lastKnownPauseState = currentPauseState
lastStateCheck = time.Now()
}
// Always update position for next comparison
lastKnownPosition = currentPos
time.Sleep(2 * time.Second) // Check every 2 seconds
}
}
}
}()
// Get skip times Parallel
go func() {
err = internal.GetAndParseAniSkipData(anime.MalId, anime.Ep.Number, 1, &anime)
if err != nil {
internal.Log("Error getting and parsing AniSkip data: " + err.Error())
}
internal.Log(anime.Ep.SkipTimes)
}()
// Get video duration
go func() {
for {
if anime.Ep.Started {
if anime.Ep.Duration == 0 {
// Get video duration
durationPos, err := internal.MPVSendCommand(anime.Ep.Player.SocketPath, []interface{}{"get_property", "duration"})
if err != nil {
internal.Log("Error getting video duration: " + err.Error())
} else if durationPos != nil {
if duration, ok := durationPos.(float64); ok {
anime.Ep.Duration = int(duration + 0.5) // Round to nearest integer
internal.Log(fmt.Sprintf("Video duration: %d seconds", anime.Ep.Duration))
// Initialize Discord presence with correct duration (first time with real duration)
if userCurdConfig.DiscordPresence {
isPaused, _ := internal.MPVSendCommand(anime.Ep.Player.SocketPath, []interface{}{"get_property", "pause"})
currentPos := 0
if timePos, err := internal.MPVSendCommand(anime.Ep.Player.SocketPath, []interface{}{"get_property", "time-pos"}); err == nil && timePos != nil {
if pos, ok := timePos.(float64); ok {
currentPos = int(pos + 0.5)
}
}
pauseState := false
if isPaused != nil {
pauseState = isPaused.(bool)
}
internal.Log("Initializing Discord presence with real video duration")
err = internal.DiscordPresence(anime, pauseState, currentPos, anime.Ep.Duration, userCurdConfig.DiscordClientId)
if err != nil {
internal.Log("Discord presence error: " + err.Error())
}
}
} else {
internal.Log("Error: duration is not a float64")
}
}
break
}
}
time.Sleep(1 * time.Second)
}
}()
// Thread for continuous next episode prompt in CLI mode (throughout episode duration)
go func() {
if userCurdConfig.NextEpisodePrompt && !userCurdConfig.RofiSelection {
internal.NextEpisodePromptContinuous(&userCurdConfig, databaseFile, user.Token)
// If the function returns, it means user made a decision
// Exit the skip loop - only close if not already closed
select {
case isClosed := <-skipLoopClosed:
if !isClosed {
close(skipLoopDone)
skipLoopClosed <- true // Mark as closed
}
default:
// Channel is busy, another goroutine is handling closure
}
}
}()
wg.Add(1)
// Thread to update playback time in database
go func() {
defer wg.Done()
for {
select {
case <-skipLoopDone:
return
default:
time.Sleep(1 * time.Second)
// Get current playback time
// internal.Log("Getting playback time "+anime.Ep.Player.SocketPath)
timePos, err := internal.MPVSendCommand(anime.Ep.Player.SocketPath, []interface{}{"get_property", "time-pos"})
if err != nil {
internal.Log("Error getting playback time: " + err.Error())
// For CLI mode with next episode prompt, let the continuous prompt handle everything
if userCurdConfig.NextEpisodePrompt && !userCurdConfig.RofiSelection {
continue
}
// Check if the error is due to invalid JSON
// User closed the video
if anime.Ep.Started {
percentageWatched := internal.PercentageWatched(anime.Ep.Player.PlaybackTime, anime.Ep.Duration)
// Episode is completed
internal.Log(fmt.Sprint(percentageWatched))
internal.Log(fmt.Sprint(anime.Ep.Player.Speed))
internal.Log(fmt.Sprint(anime.Ep.Player.PlaybackTime))
internal.Log(fmt.Sprint(anime.Ep.Duration))
internal.Log(fmt.Sprint(userCurdConfig.PercentageToMarkComplete))
if int(percentageWatched) >= userCurdConfig.PercentageToMarkComplete {
anime.Ep.IsCompleted = true
if !userCurdConfig.NextEpisodePrompt {
internal.StartNextEpisode(&anime, &userCurdConfig, databaseFile, user.Token)
} else {
// For Rofi mode, show prompt immediately after completion
if userCurdConfig.RofiSelection {
shouldContinue := internal.NextEpisodePromptRofi(&userCurdConfig)
if shouldContinue {
internal.StartNextEpisode(&anime, &userCurdConfig, databaseFile, user.Token)
} else {
// Episode was already marked as completed above
// Handle completion if this was the last episode
if anime.Ep.Number == anime.TotalEpisodes {
internal.HandleLastEpisodeCompletion(&userCurdConfig, &anime, user.Token)
}
// Update local database with completed episode
err := internal.LocalUpdateAnime(databaseFile, anime.AnilistId, anime.ProviderId, anime.Ep.Number, anime.Ep.Player.PlaybackTime, internal.ConvertSecondsToMinutes(anime.Ep.Duration), internal.GetAnimeName(anime), internal.GetProvider().Name())
if err != nil {
internal.Log("Error updating local database on quit: " + err.Error())
}
// Update Anilist progress if not rewatching
if !anime.Rewatching {
err = internal.UpdateAnimeProgress(user.Token, anime.AnilistId, anime.Ep.Number)
if err != nil {
internal.Log("Error updating Anilist progress on quit: " + err.Error())
} else {
internal.CurdOut(fmt.Sprintf("Episode completed! Progress updated: %d", anime.Ep.Number))
}
}
internal.ExitCurd(nil)
}
} else {
// For CLI mode, let the continuous prompt handle it
internal.Log("Episode completed, exiting monitoring to let CLI prompt handle next episode")
}
// Exit the skip loop - only close if not already closed
select {
case isClosed := <-skipLoopClosed:
if !isClosed {
close(skipLoopDone)
skipLoopClosed <- true // Mark as closed
}
default:
// Channel is busy, another goroutine is handling closure
}
return
}
} else {
internal.Log("Episode is not completed, exiting")
internal.ExitCurd(nil)
}
// Exit the skip loop - only close if not already closed
select {
case isClosed := <-skipLoopClosed:
if !isClosed {
close(skipLoopDone)
skipLoopClosed <- true // Mark as closed
}
default:
// Channel is busy, another goroutine is handling closure
}
return
}
}
// Convert timePos to integer
if timePos != nil {
if !anime.Ep.Started {
anime.Ep.Started = true
// Set the playback speed
if userCurdConfig.SaveMpvSpeed {
speedCmd := []interface{}{"set_property", "speed", anime.Ep.Player.Speed}
_, err := internal.MPVSendCommand(anime.Ep.Player.SocketPath, speedCmd)
if err != nil {
internal.Log("Error setting playback speed: " + err.Error())
}
}
// Apply OP/ED Chapters
err = internal.SendSkipTimesToMPV(&anime)
if err != nil {
internal.Log("Error sending skip times to MPV: " + err.Error())
}
}
// If resume is true, seek to the playback time
if anime.Ep.Resume {
internal.SeekMPV(anime.Ep.Player.SocketPath, anime.Ep.Player.PlaybackTime)
anime.Ep.Resume = false
}
animePosition, ok := timePos.(float64)
if !ok {
internal.Log("Error: timePos is not a float64")
continue
}
anime.Ep.Player.PlaybackTime = int(animePosition + 0.5) // Round to nearest integer
// Update Local Database
err = internal.LocalUpdateAnime(databaseFile, anime.AnilistId, anime.ProviderId, anime.Ep.Number, anime.Ep.Player.PlaybackTime, internal.ConvertSecondsToMinutes(anime.Ep.Duration), internal.GetAnimeName(anime), internal.GetProvider().Name())
if err != nil {
internal.Log("Error updating local database: " + err.Error())
}
}
// Check if anything is playing, if nothing is playing and episode was started, handle completion
hasPlayback, err := internal.HasActivePlayback(anime.Ep.Player.SocketPath)
if err != nil {
internal.Log("Error checking playback status: " + err.Error())
} else if !hasPlayback && anime.Ep.Started {
// Wait for a moment to allow playback to start
time.Sleep(2 * time.Second) // Wait for 2 seconds
// Check playback status again
hasPlayback, err = internal.HasActivePlayback(anime.Ep.Player.SocketPath)
if err != nil {
internal.Log("Error checking playback status: " + err.Error())
} else if !hasPlayback {
// For CLI mode with next episode prompt, let the continuous prompt handle everything
if userCurdConfig.NextEpisodePrompt && !userCurdConfig.RofiSelection {
continue
}
// Nothing is playing, check percentage watched
percentageWatched := internal.PercentageWatched(anime.Ep.Player.PlaybackTime, anime.Ep.Duration)
// fmt.Printf("[DEBUG] Playback stopped - Percentage watched: %d%%, Required: %d%%\n",
// int(percentageWatched),
// userCurdConfig.PercentageToMarkComplete)
if int(percentageWatched) >= userCurdConfig.PercentageToMarkComplete {
anime.Ep.IsCompleted = true
if !userCurdConfig.NextEpisodePrompt {
internal.StartNextEpisode(&anime, &userCurdConfig, databaseFile, user.Token)
} else {
// For Rofi mode, show prompt immediately after completion
if userCurdConfig.RofiSelection {
shouldContinue := internal.NextEpisodePromptRofi(&userCurdConfig)
if shouldContinue {
internal.StartNextEpisode(&anime, &userCurdConfig, databaseFile, user.Token)
} else {
// Episode was already marked as completed above
// Update local database with completed episode
err := internal.LocalUpdateAnime(databaseFile, anime.AnilistId, anime.ProviderId, anime.Ep.Number, anime.Ep.Player.PlaybackTime, internal.ConvertSecondsToMinutes(anime.Ep.Duration), internal.GetAnimeName(anime), internal.GetProvider().Name())
if err != nil {
internal.Log("Error updating local database on quit: " + err.Error())
}
// Update Anilist progress if not rewatching
if !anime.Rewatching {
err = internal.UpdateAnimeProgress(user.Token, anime.AnilistId, anime.Ep.Number)
if err != nil {
internal.Log("Error updating Anilist progress on quit: " + err.Error())
} else {
internal.CurdOut(fmt.Sprintf("Episode completed! Progress updated: %d", anime.Ep.Number))
}
}
internal.ExitCurd(nil)
}
} else {
// For CLI mode, update progress immediately since episode is 85%+ complete
// Update local database with completed episode
err := internal.LocalUpdateAnime(databaseFile, anime.AnilistId, anime.ProviderId, anime.Ep.Number, anime.Ep.Player.PlaybackTime, internal.ConvertSecondsToMinutes(anime.Ep.Duration), internal.GetAnimeName(anime), internal.GetProvider().Name())
if err != nil {
internal.Log("Error updating local database on completion: " + err.Error())
}
// Update Anilist progress if not rewatching
if !anime.Rewatching {
err = internal.UpdateAnimeProgress(user.Token, anime.AnilistId, anime.Ep.Number)
if err != nil {
internal.Log("Error updating Anilist progress on completion: " + err.Error())
} else {
internal.CurdOut(fmt.Sprintf("Episode completed! Progress updated: %d", anime.Ep.Number))
}
}
internal.Log("Episode completed, updated progress, exiting monitoring to let CLI prompt handle next episode")
}
// Exit the skip loop - only close if not already closed
select {
case isClosed := <-skipLoopClosed:
if !isClosed {
close(skipLoopDone)
skipLoopClosed <- true // Mark as closed
}
default:
// Channel is busy, another goroutine is handling closure
}
return
}
} else {
internal.Log("Episode is not completed, exiting")
internal.ExitCurd(nil)
}
// Exit the skip loop - only close if not already closed
select {
case isClosed := <-skipLoopClosed:
if !isClosed {
close(skipLoopDone)
skipLoopClosed <- true // Mark as closed
}
default:
// Channel is busy, another goroutine is handling closure
}
return
}
}
}
}
}()
// Skip OP and ED and Save MPV Speed
skipLoop:
for {
select {
case <-skipLoopDone:
// Exit signal received, break out of the skipLoop
break skipLoop
default:
if userCurdConfig.SkipOp {
if anime.Ep.Player.PlaybackTime > anime.Ep.SkipTimes.Op.Start && anime.Ep.Player.PlaybackTime < anime.Ep.SkipTimes.Op.Start+2 && anime.Ep.SkipTimes.Op.Start != anime.Ep.SkipTimes.Op.End {
internal.SeekMPV(anime.Ep.Player.SocketPath, anime.Ep.SkipTimes.Op.End)
}
}
if userCurdConfig.SkipEd {
if anime.Ep.Player.PlaybackTime > anime.Ep.SkipTimes.Ed.Start && anime.Ep.Player.PlaybackTime < anime.Ep.SkipTimes.Ed.Start+2 && anime.Ep.SkipTimes.Ed.Start != anime.Ep.SkipTimes.Ed.End {
internal.SeekMPV(anime.Ep.Player.SocketPath, anime.Ep.SkipTimes.Ed.End)
}
}
_, err := internal.MPVSendCommand(anime.Ep.Player.SocketPath, []interface{}{"get_property", "time-pos"})
if err == nil && anime.Ep.Started {
anime.Ep.Player.Speed, err = internal.GetMPVPlaybackSpeed(anime.Ep.Player.SocketPath)
if err != nil {
internal.Log("Failed to get mpv speed " + err.Error())
}
}
}
time.Sleep(1 * time.Second) // Wait before checking again
}
// Wait for all goroutines to finish before starting the next iteration
wg.Wait()
// Reset the WaitGroup for the next loop
wg = sync.WaitGroup{}
// Exit the program if we're starting an episode beyond the total episodes
if anime.Ep.Number > anime.TotalEpisodes && anime.TotalEpisodes > 0 {
internal.CurdOut("Reached end of series")
internal.ExitCurd(nil)
}
if anime.Ep.IsCompleted && !anime.Rewatching {
// Update progress for both regular episodes and skipped fillers
if anime.TotalEpisodes > 0 && anime.Ep.Number-1 != anime.TotalEpisodes {
go func() {
// Update progress for regular episodes
err = internal.UpdateAnimeProgress(user.Token, anime.AnilistId, anime.Ep.Number-1)
if err != nil {
internal.Log("Error updating Anilist progress: " + err.Error())
}
}()
} else {
// Update progress for last episode
// Exit MPV
internal.ExitMPV(anime.Ep.Player.SocketPath)
err = internal.UpdateAnimeProgress(user.Token, anime.AnilistId, anime.Ep.Number-1)
if err != nil {
internal.Log("Error updating Anilist progress: " + err.Error())
}
}
anime.Ep.IsCompleted = false
// Only mark as complete and prompt for rating if we've reached the total episodes
// AND the anime is not currently airing (total episodes > 0)
if anime.Ep.Number-1 == anime.TotalEpisodes && userCurdConfig.ScoreOnCompletion && anime.TotalEpisodes > 0 {
// Get updated anime data to check if it's still airing
updatedAnime, err := internal.GetAnimeDataByID(anime.AnilistId, user.Token)
if err != nil {
internal.Log("Error getting updated anime data: " + err.Error())
} else if !updatedAnime.IsAiring {
anime.Ep.Number = anime.Ep.Number - 1
internal.CurdOut("Completed anime.")
err = internal.RateAnime(user.Token, anime.AnilistId)
if err != nil {
internal.Log("Error rating anime: " + err.Error())
internal.CurdOut("Error rating anime: " + err.Error())
}
internal.LocalDeleteAnime(databaseFile, anime.AnilistId, anime.ProviderId)
internal.ExitCurd(nil)
}
}
}
if anime.Rewatching && anime.Ep.IsCompleted && anime.Ep.Number-1 == anime.TotalEpisodes {
anime.Ep.Number = anime.Ep.Number - 1
internal.CurdOut("Completed anime. (Rewatching so no scoring)")
internal.LocalDeleteAnime(databaseFile, anime.AnilistId, anime.ProviderId)
internal.ExitCurd(nil)
}
// Handle next episode logic based on config
if anime.Ep.IsCompleted {
if userCurdConfig.NextEpisodePrompt {
if !userCurdConfig.RofiSelection {
// For CLI mode, the continuous prompt handles everything
internal.CurdOut("CLI mode: continuous prompt handling next episode logic")
}
// For both modes, if we reach here, it means the monitoring thread exited
// and the episode should transition. Let the normal flow continue.
} else {
// When NextEpisodePrompt is off, continue automatically
internal.StartNextEpisode(&anime, &userCurdConfig, databaseFile, user.Token)
continue
}
}
// Wait for up to 5 seconds for prefetched links to become available
for i := 0; i < 5; i++ {
if anime.Ep.NextEpisode.Number == anime.Ep.Number && len(anime.Ep.NextEpisode.Links) > 0 {
internal.Log("Using prefetched next episode link")
anime.Ep.Links = anime.Ep.NextEpisode.Links
break
}
time.Sleep(1 * time.Second)
}
// If we still don't have links, get them now
if len(anime.Ep.Links) == 0 {
links, err := internal.GetEpisodeURL(userCurdConfig, anime.ProviderId, anime.Ep.Number)
if err != nil {
internal.Log("Failed to get episode links: " + err.Error())
internal.CurdOut("Failed to get episode links. Try again later.")
internal.ExitCurd(fmt.Errorf("failed to get episode links: %v", err))
return
}
anime.Ep.Links = links
}
// Verify that we have links before starting
if len(anime.Ep.Links) == 0 {
internal.CurdOut("No episode links found. Try again later.")
internal.ExitCurd(fmt.Errorf("no episode links found"))
return
}
}
}
================================================
FILE: flake.nix
================================================
{
description = "Watch anime in cli with Anilist Integration and Discord RPC ";
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
systems.url = "github:nix-systems/default";
};
outputs = {
nixpkgs,
systems,
self,
...
}: let
eachSystem = nixpkgs.lib.genAttrs (import systems);
in {
packages = eachSystem (system: let
package = nixpkgs.legacyPackages.${system}.callPackage ./package.nix {};
in {
default = package;
curd = package;
});
devShells = eachSystem (system: {
default = nixpkgs.legacyPackages.${system}.mkShellNoCC {
inputsFrom = [self.packages.${system}.default];
};
});
formatter = eachSystem (system: nixpkgs.legacyPackages.${system}.alejandra);
};
}
================================================
FILE: go.mod
================================================
module github.com/wraient/curd
go 1.21
require (
github.com/Microsoft/go-winio v0.6.2
github.com/charmbracelet/bubbletea v1.3.3
github.com/charmbracelet/lipgloss v1.0.0
github.com/gen2brain/beeep v0.0.0-20240516210008-9c006672e7f4
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c
github.com/tr1xem/go-discordrpc v1.0.0
)
require (
github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect
github.com/charmbracelet/x/ansi v0.8.0 // indirect
github.com/charmbracelet/x/term v0.2.1 // indirect
github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f // indirect
github.com/go-rod/rod v0.116.2 // indirect
github.com/go-toast/toast v0.0.0-20190211030409-01e6764cf0a4 // indirect
github.com/godbus/dbus/v5 v5.1.0 // indirect
github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/mattn/go-localereader v0.0.1 // indirect
github.com/mattn/go-runewidth v0.0.16 // indirect
github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 // indirect
github.com/muesli/cancelreader v0.2.2 // indirect
github.com/muesli/termenv v0.15.2 // indirect
github.com/nu7hatch/gouuid v0.0.0-20131221200532-179d4d0c4d8d // indirect
github.com/rivo/uniseg v0.4.7 // indirect
github.com/tadvi/systray v0.0.0-20190226123456-11a2b8fa57af // indirect
github.com/ysmood/fetchup v0.2.3 // indirect
github.com/ysmood/goob v0.4.0 // indirect
github.com/ysmood/got v0.40.0 // indirect
github.com/ysmood/gson v0.7.3 // indirect
github.com/ysmood/leakless v0.9.0 // indirect
golang.org/x/sync v0.11.0 // indirect
golang.org/x/sys v0.30.0 // indirect
golang.org/x/text v0.3.8 // indirect
gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce // indirect
)
================================================
FILE: go.sum
================================================
github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY=
github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU=
github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k=
github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8=
github.com/charmbracelet/bubbletea v1.3.3 h1:WpU6fCY0J2vDWM3zfS3vIDi/ULq3SYphZhkAGGvmEUY=
github.com/charmbracelet/bubbletea v1.3.3/go.mod h1:dtcUCyCGEX3g9tosuYiut3MXgY/Jsv9nKVdibKKRRXo=
github.com/charmbracelet/lipgloss v1.0.0 h1:O7VkGDvqEdGi93X+DeqsQ7PKHDgtQfF8j8/O2qFMQNg=
github.com/charmbracelet/lipgloss v1.0.0/go.mod h1:U5fy9Z+C38obMs+T+tJqst9VGzlOYGj4ri9reL3qUlo=
github.com/charmbracelet/x/ansi v0.8.0 h1:9GTq3xq9caJW8ZrBTe0LIe2fvfLR/bYXKTx2llXn7xE=
github.com/charmbracelet/x/ansi v0.8.0/go.mod h1:wdYl/ONOLHLIVmQaxbIYEC/cRKOQyjTkowiI4blgS9Q=
github.com/charmbracelet/x/term v0.2.1 h1:AQeHeLZ1OqSXhrAWpYUtZyX1T3zVxfpZuEQMIQaGIAQ=
github.com/charmbracelet/x/term v0.2.1/go.mod h1:oQ4enTYFV7QN4m0i9mzHrViD7TQKvNEEkHUMCmsxdUg=
github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f h1:Y/CXytFA4m6baUTXGLOoWe4PQhGxaX0KpnayAqC48p4=
github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f/go.mod h1:vw97MGsxSvLiUE2X8qFplwetxpGLQrlU1Q9AUEIzCaM=
github.com/gen2brain/beeep v0.0.0-20240516210008-9c006672e7f4 h1:ygs9POGDQpQGLJPlq4+0LBUmMBNox1N4JSpw+OETcvI=
github.com/gen2brain/beeep v0.0.0-20240516210008-9c006672e7f4/go.mod h1:0W7dI87PvXJ1Sjs0QPvWXKcQmNERY77e8l7GFhZB/s4=
github.com/go-rod/rod v0.116.2 h1:A5t2Ky2A+5eD/ZJQr1EfsQSe5rms5Xof/qj296e+ZqA=
github.com/go-rod/rod v0.116.2/go.mod h1:H+CMO9SCNc2TJ2WfrG+pKhITz57uGNYU43qYHh438Mg=
github.com/go-toast/toast v0.0.0-20190211030409-01e6764cf0a4 h1:qZNfIGkIANxGv/OqtnntR4DfOY2+BgwR60cAcu/i3SE=
github.com/go-toast/toast v0.0.0-20190211030409-01e6764cf0a4/go.mod h1:kW3HQ4UdaAyrUCSSDR4xUzBKW6O2iA4uHhk7AtyYp10=
github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk=
github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY=
github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mattn/go-localereader v0.0.1 h1:ygSAOl7ZXTx4RdPYinUpg6W99U8jWvWi9Ye2JC/oIi4=
github.com/mattn/go-localereader v0.0.1/go.mod h1:8fBrzywKY7BI3czFoHkuzRoWE9C+EiG4R1k4Cjx5p88=
github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc=
github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 h1:ZK8zHtRHOkbHy6Mmr5D264iyp3TiX5OmNcI5cIARiQI=
github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6/go.mod h1:CJlz5H+gyd6CUWT45Oy4q24RdLyn7Md9Vj2/ldJBSIo=
github.com/muesli/cancelreader v0.2.2 h1:3I4Kt4BQjOR54NavqnDogx/MIoWBFa0StPA8ELUXHmA=
github.com/muesli/cancelreader v0.2.2/go.mod h1:3XuTXfFS2VjM+HTLZY9Ak0l6eUKfijIfMUZ4EgX0QYo=
github.com/muesli/termenv v0.15.2 h1:GohcuySI0QmI3wN8Ok9PtKGkgkFIk7y6Vpb5PvrY+Wo=
github.com/muesli/termenv v0.15.2/go.mod h1:Epx+iuz8sNs7mNKhxzH4fWXGNpZwUaJKRS1noLXviQ8=
github.com/nu7hatch/gouuid v0.0.0-20131221200532-179d4d0c4d8d h1:VhgPp6v9qf9Agr/56bj7Y/xa04UccTW04VP0Qed4vnQ=
github.com/nu7hatch/gouuid v0.0.0-20131221200532-179d4d0c4d8d/go.mod h1:YUTz3bUH2ZwIWBy3CJBeOBEugqcmXREj14T+iG/4k4U=
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c h1:+mdjkGKdHQG3305AYmdv1U2eRNDiU2ErMBj1gwrq8eQ=
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c/go.mod h1:7rwL4CYBLnjLxUqIJNnCWiEdr3bn6IUYi15bNlnbCCU=
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
github.com/tadvi/systray v0.0.0-20190226123456-11a2b8fa57af h1:6yITBqGTE2lEeTPG04SN9W+iWHCRyHqlVYILiSXziwk=
github.com/tadvi/systray v0.0.0-20190226123456-11a2b8fa57af/go.mod h1:4F09kP5F+am0jAwlQLddpoMDM+iewkxxt6nxUQ5nq5o=
github.com/tr1xem/go-discordrpc v1.0.0 h1:iWW740MP2hkBqjehlvjRtQT7+DDaJ4qQ4o1vo+ImMug=
github.com/tr1xem/go-discordrpc v1.0.0/go.mod h1:DD//cKGwNjTSFysXlyjEUN/pSH2Z/HcFAnlOiE7wX/k=
github.com/ysmood/fetchup v0.2.3 h1:ulX+SonA0Vma5zUFXtv52Kzip/xe7aj4vqT5AJwQ+ZQ=
github.com/ysmood/fetchup v0.2.3/go.mod h1:xhibcRKziSvol0H1/pj33dnKrYyI2ebIvz5cOOkYGns=
github.com/ysmood/goob v0.4.0 h1:HsxXhyLBeGzWXnqVKtmT9qM7EuVs/XOgkX7T6r1o1AQ=
github.com/ysmood/goob v0.4.0/go.mod h1:u6yx7ZhS4Exf2MwciFr6nIM8knHQIE22lFpWHnfql18=
github.com/ysmood/got v0.40.0 h1:ZQk1B55zIvS7zflRrkGfPDrPG3d7+JOza1ZkNxcc74Q=
github.com/ysmood/got v0.40.0/go.mod h1:W7DdpuX6skL3NszLmAsC5hT7JAhuLZhByVzHTq874Qg=
github.com/ysmood/gotrace v0.6.0/go.mod h1:TzhIG7nHDry5//eYZDYcTzuJLYQIkykJzCRIo4/dzQM=
github.com/ysmood/gson v0.7.3 h1:QFkWbTH8MxyUTKPkVWAENJhxqdBa4lYTQWqZCiLG6kE=
github.com/ysmood/gson v0.7.3/go.mod h1:3Kzs5zDl21g5F/BlLTNcuAGAYLKt2lV5G8D1zF3RNmg=
github.com/ysmood/leakless v0.9.0 h1:qxCG5VirSBvmi3uynXFkcnLMzkphdh3xx5FtrORwDCU=
github.com/ysmood/leakless v0.9.0/go.mod h1:R8iAXPRaG97QJwqxs74RdwzcRHT1SWCGTNqY8q0JvMQ=
golang.org/x/sync v0.11.0 h1:GGz8+XQP4FvTTrjZPzNKTMFtSXH80RAzG+5ghFPgK9w=
golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc=
golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/text v0.3.8 h1:nAL+RVCQ9uMn3vJZbV+MRnydTJFPf8qqY42YiA6MrqY=
golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce h1:+JknDZhAj8YMt7GC73Ei8pv4MzjDUNPHgQWJdtMAaDU=
gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce/go.mod h1:5AcXVHNjg+BDxry382+8OKon8SEWiKktQR07RKPsv1c=
================================================
FILE: internal/anilist.go
================================================
package internal
import (
"bytes"
"encoding/json"
"fmt"
"io"
"net/http"
"os"
"path/filepath"
"sort"
"strconv"
"strings"
)
// FindKeyByValue searches for a key associated with a given value in a map[string]string
func FindKeyByValue(m map[string]string, value string) (string, error) {
for key, val := range m {
if val == value {
return key, nil // Return the key and true if the value is found
}
}
return "", fmt.Errorf("no key with value %v", value) // Return empty string and false if the value is not found
}
// GetAnimeMap takes an AnimeList and returns a map with media.id as key and media.title.english as value.
func GetAnimeMap(animeList AnimeList) map[string]string {
animeMap := make(map[string]string)
userCurdConfig := GetGlobalConfig()
// Helper function to populate the map from a slice of entries
populateMap := func(entries []Entry) {
for _, entry := range entries {
// Only include entries with a non-empty English title
if entry.Media.Title.English != "" && userCurdConfig.AnimeNameLanguage == "english" {
animeMap[strconv.Itoa(entry.Media.ID)] = entry.Media.Title.English
} else {
animeMap[strconv.Itoa(entry.Media.ID)] = entry.Media.Title.Romaji
}
}
}
// Populate the map for each category
populateMap(animeList.Watching)
populateMap(animeList.Completed)
populateMap(animeList.Paused)
populateMap(animeList.Dropped)
populateMap(animeList.Planning)
populateMap(animeList.Rewatching) // Add Rewatching list
return animeMap
}
// GetAnimeMapPreview takes an AnimeList and returns a map with media.id as key and media.title.english as value.
func GetAnimeMapPreview(animeList AnimeList) map[string]RofiSelectPreview {
userCurdConfig := GetGlobalConfig()
animeMap := make(map[string]RofiSelectPreview)
// Helper function to populate the map from a slice of entries
populateMap := func(entries []Entry) {
for _, entry := range entries {
// Only include entries with a non-empty English title
Log(fmt.Errorf("AnimeNameLanguage: %v", userCurdConfig.AnimeNameLanguage))
if entry.Media.Title.English != "" && userCurdConfig.AnimeNameLanguage == "english" {
animeMap[strconv.Itoa(entry.Media.ID)] = RofiSelectPreview{
Title: entry.Media.Title.English,
CoverImage: entry.CoverImage,
}
} else {
animeMap[strconv.Itoa(entry.Media.ID)] = RofiSelectPreview{
Title: entry.Media.Title.Romaji,
CoverImage: entry.CoverImage,
}
}
}
}
// Populate the map for each category
populateMap(animeList.Watching)
populateMap(animeList.Completed)
populateMap(animeList.Paused)
populateMap(animeList.Dropped)
populateMap(animeList.Planning)
populateMap(animeList.Rewatching) // Add Rewatching list
return animeMap
}
// fuzzy matching w/ Levenshtein distance
func levenshtein(a, b string) int {
a = strings.ToLower(a)
b = strings.ToLower(b)
ar, br := []rune(a), []rune(b)
alen, blen := len(ar), len(br)
if alen == 0 {
return blen
}
if blen == 0 {
return alen
}
matrix := make([][]int, alen+1)
for i := range matrix {
matrix[i] = make([]int, blen+1)
}
for i := 0; i <= alen; i++ {
matrix[i][0] = i
}
for j := 0; j <= blen; j++ {
matrix[0][j] = j
}
for i := 1; i <= alen; i++ {
for j := 1; j <= blen; j++ {
cost := 0
if ar[i-1] != br[j-1] {
cost = 1
}
matrix[i][j] = min3(
matrix[i-1][j]+1,
matrix[i][j-1]+1,
matrix[i-1][j-1]+cost,
)
}
}
return matrix[alen][blen]
}
func min3(a, b, c int) int {
if a < b && a < c {
return a
}
if b < c {
return b
}
return c
}
// SearchAnimeAnilist sends the query to AniList and returns a map of title to ID
func SearchAnimeAnilistPreview(query, token string) (map[string]RofiSelectPreview, error) {
url := "https://graphql.anilist.co"
queryString := `
query ($search: String) {
Page(page: 1, perPage: 50) {
media(search: $search, type: ANIME) {
id
title {
romaji
english
native
}
coverImage {
large
}
}
}
}`
variables := map[string]string{"search": query}
requestBody, err := json.Marshal(map[string]interface{}{
"query": queryString,
"variables": variables,
})
if err != nil {
return nil, fmt.Errorf("failed to marshal request body: %w", err)
}
req, err := http.NewRequest("POST", url, bytes.NewBuffer(requestBody))
if err != nil {
return nil, fmt.Errorf("failed to create new request: %w", err)
}
req.Header.Set("Authorization", "Bearer "+token)
req.Header.Set("Content-Type", "application/json")
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
return nil, fmt.Errorf("failed to make request: %w", err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
body, _ := io.ReadAll(resp.Body)
return nil, fmt.Errorf("failed to search for anime. Status Code: %d, Response: %s", resp.StatusCode, string(body))
}
body, err := io.ReadAll(resp.Body)
if err != nil {
return nil, fmt.Errorf("failed to read response body: %w", err)
}
var responseData map[string]ResponseData
err = json.Unmarshal(body, &responseData)
if err != nil {
return nil, fmt.Errorf("failed to unmarshal response: %w", err)
}
animeList := responseData["data"].Page.Media
animeDict := make(map[string]RofiSelectPreview)
type scoredAnime struct {
id string
title string
cover string
score int
}
var scored []scoredAnime
for _, anime := range animeList {
idStr := strconv.Itoa(anime.ID)
title := anime.Title.English
if title == "" {
title = anime.Title.Romaji
}
cover := anime.CoverImage.Large
score := levenshtein(title, query)
scored = append(scored, scoredAnime{idStr, title, cover, score})
}
sort.Slice(scored, func(i, j int) bool {
return scored[i].score < scored[j].score
})
for i, s := range scored {
if i >= 10 {
break
}
animeDict[s.id] = RofiSelectPreview{
Title: s.title,
CoverImage: s.cover,
}
}
return animeDict, nil
}
// SearchAnimeAnilist sends the query to AniList and returns a map of title to ID
func SearchAnimeAnilist(query, token string) ([]SelectionOption, error) {
url := "https://graphql.anilist.co"
queryString := `
query ($search: String) {
Page(page: 1, perPage: 50) {
media(search: $search, type: ANIME) {
id
title {
romaji
english
native
}
}
}
}`
variables := map[string]string{"search": query}
requestBody, err := json.Marshal(map[string]interface{}{
"query": queryString,
"variables": variables,
})
if err != nil {
return nil, fmt.Errorf("failed to marshal request body: %w", err)
}
req, err := http.NewRequest("POST", url, bytes.NewBuffer(requestBody))
if err != nil {
return nil, fmt.Errorf("failed to create new request: %w", err)
}
req.Header.Set("Authorization", "Bearer "+token)
req.Header.Set("Content-Type", "application/json")
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
return nil, fmt.Errorf("failed to make request: %w", err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
body, _ := io.ReadAll(resp.Body)
return nil, fmt.Errorf("failed to search for anime. Status Code: %d, Response: %s", resp.StatusCode, string(body))
}
body, err := io.ReadAll(resp.Body)
if err != nil {
return nil, fmt.Errorf("failed to read response body: %w", err)
}
var responseData map[string]ResponseData
err = json.Unmarshal(body, &responseData)
if err != nil {
return nil, fmt.Errorf("failed to unmarshal response: %w", err)
}
animeList := responseData["data"].Page.Media
var results []SelectionOption
type scoredAnime struct {
id string
title string
score int
}
var scored []scoredAnime
for _, anime := range animeList {
idStr := strconv.Itoa(anime.ID)
title := anime.Title.English
if title == "" {
title = anime.Title.Romaji
}
score := levenshtein(title, query)
scored = append(scored, scoredAnime{idStr, title, score})
}
sort.Slice(scored, func(i, j int) bool {
return scored[i].score < scored[j].score
})
for i, s := range scored {
if i >= 10 {
break
}
results = append(results, SelectionOption{
Key: s.id,
Label: s.title,
})
}
return results, nil
}
// Function to get AniList user ID and username
func GetAnilistUserID(token string) (int, string, error) {
url := "https://graphql.anilist.co"
query := `
query {
Viewer {
id
name
}
}`
headers := map[string]string{
"Authorization": "Bearer " + token,
"Content-Type": "application/json",
"Accept": "application/json",
}
response, err := makePostRequest(url, query, nil, headers)
if err != nil {
return 0, "", err
}
data := response["data"].(map[string]interface{})["Viewer"].(map[string]interface{})
userID := int(data["id"].(float64))
userName := data["name"].(string)
return userID, userName, nil
}
// Function to add an anime to the watching list
func AddAnimeToWatchingList(animeID int, token string) error {
url := "https://graphql.anilist.co"
mutation := `
mutation ($mediaId: Int) {
SaveMediaListEntry (mediaId: $mediaId, status: CURRENT) {
id
status
}
}`
variables := map[string]interface{}{
"mediaId": animeID,
}
headers := map[string]string{
"Authorization": "Bearer " + token,
"Content-Type": "application/json",
}
_, err := makePostRequest(url, mutation, variables, headers)
if err != nil {
return fmt.Errorf("failed to add anime: %w", err)
}
CurdOut(fmt.Sprintf("Anime with ID %d has been added to your watching list.", animeID))
return nil
}
// Function to get MAL ID using AniList media ID
func GetAnimeMalID(anilistMediaID int) (int, error) {
url := "https://graphql.anilist.co"
query := `
query ($id: Int) {
Media(id: $id) {
idMal
}
}`
variables := map[string]interface{}{
"id": anilistMediaID,
}
response, err := makePostRequest(url, query, variables, nil)
if err != nil {
return 0, err
}
malID := int(response["data"].(map[string]interface{})["Media"].(map[string]interface{})["idMal"].(float64))
return malID, nil
}
// This function retrieves the MAL ID and cover image URL for an anime from AniList
func GetAnimeIDAndImage(anilistMediaID int) (int, string, error) {
url := "https://graphql.anilist.co"
query := `
query ($id: Int) {
Media(id: $id) {
coverImage {
large
}
idMal
}
}`
variables := map[string]interface{}{
"id": anilistMediaID,
}
response, err := makePostRequest(url, query, variables, nil)
if err != nil {
return 0, "", err
}
data := response["data"].(map[string]interface{})["Media"].(map[string]interface{})
malID := int(data["idMal"].(float64))
imageURL := data["coverImage"].(map[string]interface{})["large"].(string)
return malID, imageURL, nil
}
// Function to get user data from AniList
func GetUserData(token string, userID int) (map[string]interface{}, error) {
query := `
query ($userId: Int, $type: MediaType) {
MediaListCollection(userId: $userId, type: $type) {
lists {
entries {
media {
id
episodes
duration
title {
romaji
english
native
}
status
}
status
score
progress
repeat
startedAt {
year
month
day
}
completedAt {
year
month
day
}
}
}
}
}`
variables := map[string]interface{}{
"userId": userID,
"type": "ANIME",
}
headers := map[string]string{
"Authorization": "Bearer " + token,
"Content-Type": "application/json",
}
response, err := makePostRequest("https://graphql.anilist.co", query, variables, headers)
if err != nil {
return nil, err
}
return response, nil
}
func GetUserDataPreview(token string, userID int) (map[string]interface{}, error) {
query := `
query ($userId: Int, $type: MediaType) {
MediaListCollection(userId: $userId, type: $type) {
lists {
entries {
media {
id
episodes
duration
coverImage {
large
}
title {
romaji
english
native
}
status
}
status
score
progress
repeat
startedAt {
year
month
day
}
completedAt {
year
month
day
}
}
}
}
}`
variables := map[string]interface{}{
"userId": userID,
"type": "ANIME",
}
headers := map[string]string{
"Authorization": "Bearer " + token,
"Content-Type": "application/json",
}
response, err := makePostRequest("https://graphql.anilist.co", query, variables, headers)
if err != nil {
return nil, err
}
return response, nil
}
// Function to load a JSON file
func LoadJSONFile(filePath string) (map[string]interface{}, error) {
data, err := os.ReadFile(filepath.Clean(filePath))
if err != nil {
return nil, fmt.Errorf("failed to read file: %w", err)
}
var jsonData map[string]interface{}
err = json.Unmarshal(data, &jsonData)
if err != nil {
return nil, fmt.Errorf("failed to parse JSON: %w", err)
}
return jsonData, nil
}
// Function to search for an anime by title in user data
func SearchAnimeByTitle(jsonData map[string]interface{}, searchTitle string) []map[string]interface{} {
results := []map[string]interface{}{}
lists := jsonData["data"].(map[string]interface{})["MediaListCollection"].(map[string]interface{})["lists"].([]interface{})
for _, list := range lists {
entries := list.(map[string]interface{})["entries"].([]interface{})
for _, entry := range entries {
media := entry.(map[string]interface{})["media"].(map[string]interface{})
romajiTitle := media["title"].(map[string]interface{})["romaji"].(string)
englishTitle := media["title"].(map[string]interface{})["english"].(string)
episodes := int(media["episodes"].(float64))
duration := int(media["duration"].(float64))
if strings.Contains(strings.ToLower(romajiTitle), strings.ToLower(searchTitle)) || strings.Contains(strings.ToLower(englishTitle), strings.ToLower(searchTitle)) {
result := map[string]interface{}{
"id": media["id"],
"progress": entry.(map[string]interface{})["progress"],
"romaji_title": romajiTitle,
"english_title": englishTitle,
"episodes": episodes,
"duration": duration,
}
results = append(results, result)
}
}
}
return results
}
// Function to update anime progress
func UpdateAnimeProgress(token string, mediaID, progress int) error {
err := SaveAnimeListEntry(token, mediaID, nil, &progress, nil, nil, nil)
if err != nil {
return err
}
CurdOut(fmt.Sprint("Anime progress updated! Latest watched episode: ", progress))
return nil
}
func UpdateAnimeStatus(token string, mediaID int, status string) error {
err := SaveAnimeListEntry(token, mediaID, &status, nil, nil, nil, nil)
if err != nil {
return fmt.Errorf("failed to update anime status: %w", err)
}
statusMap := map[string]string{
"CURRENT": "Currently Watching",
"COMPLETED": "Completed",
"PAUSED": "On Hold",
"DROPPED": "Dropped",
"PLANNING": "Plan to Watch",
"REPEATING": "Rewatching",
}
CurdOut(fmt.Sprintf("Anime status updated to: %s", statusMap[status]))
return nil
}
func SaveAnimeListEntry(token string, mediaID int, status *string, progress *int, repeat *int, startedAt *FuzzyDate, completedAt *FuzzyDate) error {
url := "https://graphql.anilist.co"
query := `
mutation(
$mediaId: Int
$status: MediaListStatus
$progress: Int
$repeat: Int
$startedAt: FuzzyDateInput
$completedAt: FuzzyDateInput
) {
SaveMediaListEntry(
mediaId: $mediaId
status: $status
progress: $progress
repeat: $repeat
startedAt: $startedAt
completedAt: $completedAt
) {
id
status
progress
repeat
startedAt {
year
month
day
}
completedAt {
year
month
day
}
}
}`
variables := map[string]interface{}{
"mediaId": mediaID,
}
if status != nil {
variables["status"] = *status
}
if progress != nil {
variables["progress"] = *progress
}
if repeat != nil {
variables["repeat"] = *repeat
}
if startedAt != nil && (startedAt.Year != 0 || startedAt.Month != 0 || startedAt.Day != 0) {
variables["startedAt"] = map[string]int{
"year": startedAt.Year,
"month": startedAt.Month,
"day": startedAt.Day,
}
}
if completedAt != nil && (completedAt.Year != 0 || completedAt.Month != 0 || completedAt.Day != 0) {
variables["completedAt"] = map[string]int{
"year": completedAt.Year,
"month": completedAt.Month,
"day": completedAt.Day,
}
}
headers := map[string]string{
"Authorization": "Bearer " + token,
"Content-Type": "application/json",
}
_, err := makePostRequest(url, query, variables, headers)
if err != nil {
return err
}
return nil
}
func CompleteAnimeRewatch(token string, anime Anime) error {
status := "COMPLETED"
repeat := anime.Repeat + 1
return SaveAnimeListEntry(token, anime.AnilistId, &status, nil, &repeat, &anime.StartedAt, &anime.CompletedAt)
}
// Function to rate an anime on AniList
func RateAnime(token string, mediaID int) error {
var score float64
var err error
userCurdConfig := GetGlobalConfig()
if userCurdConfig == nil {
return fmt.Errorf("failed to get curd config")
}
if userCurdConfig.RofiSelection {
userInput, err := GetUserInputFromRofi("Enter a score for the anime (0-10)")
if err != nil {
return err
}
score, err = strconv.ParseFloat(userInput, 64)
if err != nil {
return err
}
} else {
fmt.Println("Rate this anime: ")
fmt.Scanln(&score)
}
url := "https://graphql.anilist.co"
query := `
mutation($mediaId: Int, $score: Float) {
SaveMediaListEntry(mediaId: $mediaId, score: $score) {
id
mediaId
score
}
}`
variables := map[string]interface{}{
"mediaId": mediaID,
"score": score,
}
headers := map[string]string{
"Authorization": "Bearer " + token,
"Content-Type": "application/json",
}
_, err = makePostRequest(url, query, variables, headers)
if err != nil {
return err
}
CurdOut(fmt.Sprintf("Successfully rated anime (mediaId: %d) with score: %.2f", mediaID, score))
return nil
}
// Helper function to make POST requests
func makePostRequest(url, query string, variables map[string]interface{}, headers map[string]string) (map[string]interface{}, error) {
requestBody, err := json.Marshal(map[string]interface{}{
"query": query,
"variables": variables,
})
if err != nil {
return nil, fmt.Errorf("failed to marshal request body: %w", err)
}
req, err := http.NewRequest("POST", url, bytes.NewBuffer(requestBody))
if err != nil {
return nil, fmt.Errorf("failed to create request: %w", err)
}
req.Header.Set("Content-Type", "application/json") // <-- Important!
for key, value := range headers {
req.Header.Set(key, value)
}
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
return nil, fmt.Errorf("failed to send request: %w", err)
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
if err != nil {
return nil, fmt.Errorf("failed to read response body: %w", err)
}
if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("failed with status %d: %s", resp.StatusCode, body)
}
var responseData map[string]interface{}
// Unmarshal the response into a map
err = json.Unmarshal(body, &responseData)
if err != nil {
return nil, fmt.Errorf("failed to unmarshal response: %w", err)
}
return responseData, nil
}
func ParseAnimeList(input map[string]interface{}) AnimeList {
var animeList AnimeList
toInt := func(value interface{}) int {
switch v := value.(type) {
case int:
return v
case float64:
return int(v) // You could also use int(math.Round(v)) to round
default:
return 0 // Default value for unexpected types
}
}
safeString := func(value interface{}) string {
if value == nil {
return ""
}
// Attempt to assert the value as a string
if str, ok := value.(string); ok {
return str
}
// If it's not a string, return an empty string or handle it as needed
return ""
}
parseFuzzyDate := func(value interface{}) FuzzyDate {
dateMap, ok := value.(map[string]interface{})
if !ok || dateMap == nil {
return FuzzyDate{}
}
return FuzzyDate{
Year: toInt(dateMap["year"]),
Month: toInt(dateMap["month"]),
Day: toInt(dateMap["day"]),
}
}
// Access the list entries in the input map
if input["data"] == nil {
Log("Anilist request failed")
CurdOut("Anilist request failed")
ExitCurd(fmt.Errorf("Anilist request failed"))
return animeList
}
data := input["data"].(map[string]interface{})
mediaList := data["MediaListCollection"].(map[string]interface{})["lists"].([]interface{})
for _, list := range mediaList {
entries := list.(map[string]interface{})["entries"].([]interface{})
for _, entry := range entries {
entryData := entry.(map[string]interface{})
media := entryData["media"].(map[string]interface{})
animeEntry := Entry{
Media: Media{
Duration: toInt(media["duration"]),
Episodes: toInt(media["episodes"]),
ID: toInt(media["id"]),
Title: AnimeTitle{
English: safeString(media["title"].(map[string]interface{})["english"]),
Romaji: safeString(media["title"].(map[string]interface{})["romaji"]),
Japanese: safeString(media["title"].(map[string]interface{})["native"]),
},
Status: safeString(media["status"]),
},
Progress: toInt(entryData["progress"]),
Repeat: toInt(entryData["repeat"]),
Score: entryData["score"].(float64),
Status: safeString(entryData["status"]), // Ensure status is fetched safely
StartedAt: parseFuzzyDate(entryData["startedAt"]),
CompletedAt: parseFuzzyDate(entryData["completedAt"]),
}
if coverImage, ok := media["coverImage"].(map[string]interface{}); ok {
animeEntry.CoverImage = safeString(coverImage["large"])
}
// Append entries based on their status
switch animeEntry.Status {
case "CURRENT":
animeList.Watching = append(animeList.Watching, animeEntry)
case "COMPLETED":
animeList.Completed = append(animeList.Completed, animeEntry)
case "PAUSED":
animeList.Paused = append(animeList.Paused, animeEntry)
case "DROPPED":
animeList.Dropped = append(animeList.Dropped, animeEntry)
case "PLANNING":
animeList.Planning = append(animeList.Planning, animeEntry)
case "REPEATING": // Anilist uses REPEATING for rewatching
animeList.Rewatching = append(animeList.Rewatching, animeEntry)
}
}
}
return animeList
}
// FindAnimeByID searches for an anime by its ID in the AnimeList
func FindAnimeByAnilistID(list AnimeList, idStr string) (*Entry, error) {
id, err := strconv.Atoi(idStr)
if err != nil {
return nil, fmt.Errorf("invalid ID format: %s", idStr)
}
// Define a slice of pointers to hold categories
categories := [][]Entry{
list.Watching,
list.Completed,
list.Paused,
list.Dropped,
list.Planning,
list.Rewatching, // Add Rewatching list
}
// Iterate through each category
for _, category := range categories {
for _, entry := range category {
if entry.Media.ID == id {
return &entry, nil // Return a pointer to the found entry
}
}
}
return nil, fmt.Errorf("anime with ID %d not found", id) // Return an error if not found
}
// FindAnimeByAnilistIDInAnimes searches for an anime by its AniList ID in a slice of Anime
func FindAnimeByAnilistIDInAnimes(animes []Anime, anilistID int) (*Anime, error) {
for i := range animes {
if animes[i].AnilistId == anilistID {
return &animes[i], nil
}
}
return nil, fmt.Errorf("anime with ID %d not found", anilistID)
}
// GetAnimeDataByID retrieves detailed anime data from AniList using the anime's ID and user token
func GetAnimeDataByID(id int, token string) (Anime, error) {
url := "https://graphql.anilist.co"
query := `
query ($id: Int) {
Media(id: $id, type: ANIME) {
id
episodes
status
nextAiringEpisode {
episode
}
}
}`
variables := map[string]interface{}{
"id": id,
}
headers := map[string]string{
"Authorization": "Bearer " + token,
"Content-Type": "application/json",
}
response, err := makePostRequest(url, query, variables, headers)
if err != nil {
return Anime{}, fmt.Errorf("failed to get anime data: %w", err)
}
data, ok := response["data"].(map[string]interface{})
if !ok {
return Anime{}, fmt.Errorf("invalid response format: data field missing")
}
media, ok := data["Media"].(map[string]interface{})
if !ok {
return Anime{}, fmt.Errorf("invalid response format: Media field missing")
}
anime := Anime{
AnilistId: id,
IsAiring: false,
}
// Safely handle episodes field which might be nil for currently airing shows
if episodes, ok := media["episodes"].(float64); ok {
anime.TotalEpisodes = int(episodes)
}
// Check status
if status, ok := media["status"].(string); ok {
anime.IsAiring = status == "RELEASING"
}
// Double check with nextAiringEpisode
if nextEp, ok := media["nextAiringEpisode"].(map[string]interface{}); ok && nextEp != nil {
anime.IsAiring = true
}
return anime, nil
}
// SequelInfo holds information about a sequel anime
type SequelInfo struct {
ID int
Title AnimeTitle
CoverImage string
Episodes int
Status string // "FINISHED", "RELEASING", "NOT_YET_RELEASED"
SiteURL string
}
// GetAnimeSequel fetches sequel information for a given anime from AniList
// GetAnimeSequel fetches sequel information for a given anime from AniList
func GetAnimeSequel(animeID int, token string) ([]SequelInfo, error) {
url := "https://graphql.anilist.co"
query := `
query ($id: Int) {
Media(id: $id, type: ANIME) {
relations {
edges {
relationType
node {
id
title {
romaji
english
}
coverImage {
large
}
episodes
status
siteUrl
}
}
}
}
}`
variables := map[string]interface{}{
"id": animeID,
}
headers := map[string]string{
"Authorization": "Bearer " + token,
"Content-Type": "application/json",
}
response, err := makePostRequest(url, query, variables, headers)
if err != nil {
return nil, fmt.Errorf("failed to get anime relations: %w", err)
}
data, ok := response["data"].(map[string]interface{})
if !ok {
return nil, fmt.Errorf("invalid response format: data field missing")
}
media, ok := data["Media"].(map[string]interface{})
if !ok {
return nil, fmt.Errorf("invalid response format: Media field missing")
}
relations, ok := media["relations"].(map[string]interface{})
if !ok {
return nil, nil // No relations found
}
edges, ok := relations["edges"].([]interface{})
if !ok || len(edges) == 0 {
return nil, nil // No edges found
}
var sequels []SequelInfo
// Look for a SEQUEL relation
for _, edge := range edges {
edgeData, ok := edge.(map[string]interface{})
if !ok {
continue
}
relationType, ok := edgeData["relationType"].(string)
if !ok || relationType != "SEQUEL" {
continue
}
node, ok := edgeData["node"].(map[string]interface{})
if !ok {
continue
}
var sequel SequelInfo
// Parse ID
if id, ok := node["id"].(float64); ok {
sequel.ID = int(id)
}
// Parse title
if title, ok := node["title"].(map[string]interface{}); ok {
if romaji, ok := title["romaji"].(string); ok {
sequel.Title.Romaji = romaji
}
if english, ok := title["english"].(string); ok {
sequel.Title.English = english
}
}
// Parse cover image
if coverImage, ok := node["coverImage"].(map[string]interface{}); ok {
if large, ok := coverImage["large"].(string); ok {
sequel.CoverImage = large
}
}
// Parse episodes
if episodes, ok := node["episodes"].(float64); ok {
sequel.Episodes = int(episodes)
}
// Parse status
if status, ok := node["status"].(string); ok {
sequel.Status = status
}
// Parse siteUrl
if siteUrl, ok := node["siteUrl"].(string); ok {
sequel.SiteURL = siteUrl
}
sequels = append(sequels, sequel)
}
if len(sequels) == 0 {
return nil, nil // No sequel found
}
return sequels, nil
}
// AddAnimeToList adds an anime to a specified list (CURRENT, PLANNING, PAUSED, DROPPED)
func AddAnimeToList(animeID int, status string, token string) error {
url := "https://graphql.anilist.co"
mutation := `
mutation ($mediaId: Int, $status: MediaListStatus) {
SaveMediaListEntry (mediaId: $mediaId, status: $status) {
id
status
}
}`
variables := map[string]interface{}{
"mediaId": animeID,
"status": status,
}
headers := map[string]string{
"Authorization": "Bearer " + token,
"Content-Type": "application/json",
}
_, err := makePostRequest(url, mutation, variables, headers)
if err != nil {
return fmt.Errorf("failed to add anime to list: %w", err)
}
statusMap := map[string]string{
"CURRENT": "Currently Watching",
"COMPLETED": "Completed",
"PAUSED": "On Hold",
"DROPPED": "Dropped",
"PLANNING": "Plan to Watch",
"REPEATING": "Rewatching",
}
CurdOut(fmt.Sprintf("Anime added to: %s", statusMap[status]))
return nil
}
// FindSequelInAnimeList searches for a sequel in the user's anime list and returns its status
func FindSequelInAnimeList(list AnimeList, sequelID int) (string, bool) {
// Check all categories
for _, entry := range list.Watching {
if entry.Media.ID == sequelID {
return "CURRENT", true
}
}
for _, entry := range list.Planning {
if entry.Media.ID == sequelID {
return "PLANNING", true
}
}
for _, entry := range list.Completed {
if entry.Media.ID == sequelID {
return "COMPLETED", true
}
}
for _, entry := range list.Paused {
if entry.Media.ID == sequelID {
return "PAUSED", true
}
}
for _, entry := range list.Dropped {
if entry.Media.ID == sequelID {
return "DROPPED", true
}
}
for _, entry := range list.Rewatching {
if entry.Media.ID == sequelID {
return "REWATCHING", true
}
}
return "", false
}
================================================
FILE: internal/anilist_cache.go
================================================
package internal
import (
"encoding/json"
"fmt"
"os"
"path/filepath"
"strconv"
"sync"
"time"
)
const animeListCacheFileName = "anilist_list_cache.json"
type animeListCachePayload struct {
AnimeList AnimeList `json:"anime_list"`
UpdatedAt time.Time `json:"updated_at"`
UserID int `json:"user_id"`
}
type AnimeListSync struct {
mu sync.RWMutex
current AnimeList
updates chan AnimeList
refreshDone chan struct{} // closed exactly once when the background refresh finishes
closeOnce sync.Once
}
func NewAnimeListSync(initial AnimeList) *AnimeListSync {
return &AnimeListSync{
current: initial,
updates: make(chan AnimeList, 1),
refreshDone: make(chan struct{}),
}
}
// MarkRefreshDone closes the refreshDone channel exactly once.
func (s *AnimeListSync) MarkRefreshDone() {
s.closeOnce.Do(func() { close(s.refreshDone) })
}
// RefreshDone returns a channel that is closed when the background refresh finishes.
func (s *AnimeListSync) RefreshDone() <-chan struct{} {
return s.refreshDone
}
func (s *AnimeListSync) Current() AnimeList {
s.mu.RLock()
defer s.mu.RUnlock()
return s.current
}
func (s *AnimeListSync) Replace(list AnimeList, notify bool) bool {
s.mu.Lock()
changed := !animeListEqual(s.current, list)
s.current = list
s.mu.Unlock()
if changed && notify {
select {
case s.updates <- list:
default:
select {
case <-s.updates:
default:
}
s.updates <- list
}
}
return changed
}
func (s *AnimeListSync) Updates() <-chan AnimeList {
return s.updates
}
func animeListCachePath(storagePath string) string {
return filepath.Join(os.ExpandEnv(storagePath), animeListCacheFileName)
}
func loadAnimeListCache(storagePath string, userID int) (animeListCachePayload, error) {
cacheFilePath := animeListCachePath(storagePath)
data, err := os.ReadFile(cacheFilePath)
if err != nil {
return animeListCachePayload{}, err
}
var payload animeListCachePayload
if err := json.Unmarshal(data, &payload); err != nil {
return animeListCachePayload{}, fmt.Errorf("failed to parse anime list cache: %w", err)
}
if payload.UserID != 0 && userID != 0 && payload.UserID != userID {
return animeListCachePayload{}, fmt.Errorf("anime list cache belongs to a different AniList user")
}
return payload, nil
}
func saveAnimeListCache(storagePath string, userID int, list AnimeList) error {
storagePath = os.ExpandEnv(storagePath)
if err := os.MkdirAll(storagePath, 0o755); err != nil {
return fmt.Errorf("failed to create storage directory: %w", err)
}
payload := animeListCachePayload{
AnimeList: list,
UpdatedAt: time.Now(),
UserID: userID,
}
data, err := json.MarshalIndent(payload, "", " ")
if err != nil {
return fmt.Errorf("failed to marshal anime list cache: %w", err)
}
cacheFilePath := animeListCachePath(storagePath)
tempFilePath := cacheFilePath + ".tmp"
if err := os.WriteFile(tempFilePath, data, 0o644); err != nil {
return fmt.Errorf("failed to write anime list cache: %w", err)
}
if err := os.Rename(tempFilePath, cacheFilePath); err != nil {
_ = os.Remove(tempFilePath)
return fmt.Errorf("failed to replace anime list cache: %w", err)
}
return nil
}
func animeListEqual(a, b AnimeList) bool {
left, err := json.Marshal(a)
if err != nil {
return false
}
right, err := json.Marshal(b)
if err != nil {
return false
}
return string(left) == string(right)
}
func FetchLatestAnimeList(token string, userID int) (AnimeList, error) {
userData, err := GetUserDataPreview(token, userID)
if err != nil {
return AnimeList{}, err
}
return ParseAnimeList(userData), nil
}
func refreshAnimeListInBackground(userCurdConfig *CurdConfig, user *User) {
if user == nil || user.ListSync == nil {
return
}
go func() {
// Signal done regardless of success/failure so callers never block forever.
defer user.ListSync.MarkRefreshDone()
// Only fetch the user ID when we don't already have it (first run, no cache).
// On cache hits user.Id is already seeded, so skip this extra round-trip.
if user.Id == 0 {
userID, username, err := GetAnilistUserID(user.Token)
if err != nil {
Log(fmt.Sprintf("Failed to refresh user ID in background: %v", err))
return
}
user.Id = userID
if user.Username == "" {
user.Username = username
}
}
latestList, err := FetchLatestAnimeList(user.Token, user.Id)
if err != nil {
Log(fmt.Sprintf("Failed to refresh anime list in background: %v", err))
return
}
if err := saveAnimeListCache(userCurdConfig.StoragePath, user.Id, latestList); err != nil {
Log(fmt.Sprintf("Failed to save refreshed anime list cache: %v", err))
}
user.ListSync.Replace(latestList, true)
}()
}
func InitializeUserAnimeList(userCurdConfig *CurdConfig, user *User) error {
cachedPayload, err := loadAnimeListCache(userCurdConfig.StoragePath, user.Id)
if err == nil {
// Seed user ID from cache so we skip the blocking GetAnilistUserID network call.
if user.Id == 0 && cachedPayload.UserID != 0 {
user.Id = cachedPayload.UserID
}
user.AnimeList = cachedPayload.AnimeList
user.ListSync = NewAnimeListSync(cachedPayload.AnimeList)
// Refresh user ID + anime list in the background (non-blocking).
refreshAnimeListInBackground(userCurdConfig, user)
return nil
}
if !os.IsNotExist(err) {
Log(fmt.Sprintf("Failed to load anime list cache, fetching latest instead: %v", err))
}
// No cache — blocking fetch is unavoidable on first run.
if user.Id == 0 {
userID, username, idErr := GetAnilistUserID(user.Token)
if idErr != nil {
return idErr
}
user.Id = userID
user.Username = username
}
latestList, err := FetchLatestAnimeList(user.Token, user.Id)
if err != nil {
return err
}
user.AnimeList = latestList
user.ListSync = NewAnimeListSync(latestList)
// Blocking fetch already has the freshest data — mark done immediately.
user.ListSync.MarkRefreshDone()
if err := saveAnimeListCache(userCurdConfig.StoragePath, user.Id, latestList); err != nil {
Log(fmt.Sprintf("Failed to save anime list cache: %v", err))
}
return nil
}
func RefreshUserAnimeList(userCurdConfig *CurdConfig, user *User) error {
if user.Id == 0 {
userID, username, err := GetAnilistUserID(user.Token)
if err != nil {
return err
}
user.Id = userID
if user.Username == "" {
user.Username = username
}
}
latestList, err := FetchLatestAnimeList(user.Token, user.Id)
if err != nil {
return err
}
user.AnimeList = latestList
if user.ListSync == nil {
user.ListSync = NewAnimeListSync(latestList)
} else {
user.ListSync.Replace(latestList, true)
}
if err := saveAnimeListCache(userCurdConfig.StoragePath, user.Id, latestList); err != nil {
Log(fmt.Sprintf("Failed to save anime list cache: %v", err))
}
return nil
}
func buildCategorySelectionOptions(list AnimeList, category string) []SelectionOption {
userCurdConfig := GetGlobalConfig()
options := make([]SelectionOption, 0)
for _, entry := range getEntriesByCategory(list, category) {
title := entry.Media.Title.English
if title == "" || userCurdConfig.AnimeNameLanguage == "romaji" {
title = entry.Media.Title.Romaji
}
options = append(options, SelectionOption{
Key: strconv.Itoa(entry.Media.ID),
Label: title,
})
}
return options
}
func buildCategoryPreviewOptions(list AnimeList, category string) map[string]RofiSelectPreview {
userCurdConfig := GetGlobalConfig()
options := make(map[string]RofiSelectPreview)
for _, entry := range getEntriesByCategory(list, category) {
title := entry.Media.Title.English
if title == "" || userCurdConfig.AnimeNameLanguage == "romaji" {
title = entry.Media.Title.Romaji
}
options[strconv.Itoa(entry.Media.ID)] = RofiSelectPreview{
Title: title,
CoverImage: entry.CoverImage,
}
}
return options
}
================================================
FILE: internal/anime_list.go
================================================
package internal
import (
"bytes"
"encoding/json"
"fmt"
"io"
"net/http"
"path/filepath"
"strings"
)
type anime struct {
ID string `json:"_id"`
Name string `json:"name"`
EnglishName string `json:"englishName"`
Thumbnail string `json:"thumbnail"`
AvailableEpisodes interface{} `json:"availableEpisodes"`
}
type response struct {
Data struct {
Shows struct {
Edges []anime `json:"edges"`
} `json:"shows"`
} `json:"data"`
}
func normalizeTranslationType(mode string) string {
if strings.EqualFold(strings.TrimSpace(mode), "dub") {
return "dub"
}
return "sub"
}
func alternateTranslationType(mode string) string {
if normalizeTranslationType(mode) == "dub" {
return "sub"
}
return "dub"
}
// func main() {
// // Get environment variables
// mode := "sub"
// // Query for the anime (from a file in this example)
// query := "one piece"
// // Search anime
// animeList, err := SearchAnime(string(query), mode)
// if err != nil {
// }
// fmt.Println(animeList)
// }
func searchAllAnime(query, mode string) ([]SelectionOption, error) {
preferredMode := normalizeTranslationType(mode)
alternateMode := alternateTranslationType(preferredMode)
preferredResults, preferredErr := searchAnimeByMode(query, preferredMode, preferredMode)
alternateResults, alternateErr := searchAnimeByMode(query, alternateMode, preferredMode)
if preferredErr != nil {
Log(fmt.Sprintf("Failed searching %s results for %q: %v", preferredMode, query, preferredErr))
}
if alternateErr != nil {
Log(fmt.Sprintf("Failed searching %s results for %q: %v", alternateMode, query, alternateErr))
}
if preferredErr != nil && alternateErr != nil {
return nil, preferredErr
}
animeList := make([]SelectionOption, 0, len(preferredResults)+len(alternateResults))
seen := make(map[string]struct{}, len(preferredResults)+len(alternateResults))
for _, option := range preferredResults {
animeList = append(animeList, option)
seen[option.Key] = struct{}{}
}
for _, option := range alternateResults {
if _, exists := seen[option.Key]; exists {
continue
}
animeList = append(animeList, option)
}
return animeList, nil
}
func searchAnimeByMode(query, mode, preferredMode string) ([]SelectionOption, error) {
userCurdConfig := GetGlobalConfig()
logFile = filepath.Join(GetStoragePath(), "debug.log")
const (
agent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/121.0"
allanimeRef = "https://allanime.to"
allanimeBase = "allanime.day"
allanimeAPI = "https://api." + allanimeBase + "/api"
)
mode = normalizeTranslationType(mode)
preferredMode = normalizeTranslationType(preferredMode)
animeList := make([]SelectionOption, 0)
searchGql := `query($search: SearchInput, $limit: Int, $page: Int, $translationType: VaildTranslationTypeEnumType, $countryOrigin: VaildCountryOriginEnumType) {
shows(search: $search, limit: $limit, page: $page, translationType: $translationType, countryOrigin: $countryOrigin) {
edges {
_id
name
englishName
thumbnail
availableEpisodes
__typename
}
}
}`
// Prepare the GraphQL variables
variables := map[string]interface{}{
"search": map[string]interface{}{
"allowAdult": false,
"allowUnknown": false,
"query": query,
},
"limit": 40,
"page": 1,
"translationType": mode,
"countryOrigin": "ALL",
}
// Build POST request body
requestBody, err := json.Marshal(map[string]interface{}{
"query": searchGql,
"variables": variables,
})
if err != nil {
Log(fmt.Sprintf("Error encoding request body to JSON: %v", err))
return animeList, err
}
// Make the HTTP POST request
req, err := http.NewRequest("POST", allanimeAPI, bytes.NewBuffer(requestBody))
if err != nil {
Log(fmt.Sprintf("Error creating HTTP request: %v", err))
return animeList, err
}
req.Header.Set("Content-Type", "application/json")
req.Header.Set("User-Agent", agent)
req.Header.Set("Referer", allanimeRef)
req.Header.Set("Origin", allanimeRef)
resp, err := sharedHTTPClient.Do(req)
if err != nil {
Log(fmt.Sprintf("Error making HTTP request: %v", err))
return animeList, err
}
defer resp.Body.Close()
// Read the response body
body, err := io.ReadAll(resp.Body)
if err != nil {
Log(fmt.Sprintf("Error reading response body: %v", err))
return animeList, err
}
// Debug: Log the response status and first part of the body
Log(fmt.Sprintf("Response Status: %s", resp.Status))
Log(fmt.Sprintf("Response Body (first 500 chars): %s", string(body[:min(len(body), 500)])))
// Parse the JSON response
var response response
err = json.Unmarshal(body, &response)
if err != nil {
Log(fmt.Sprintf("Error parsing JSON for query '%s': %v\nBody: %s", query, err, string(body)))
return animeList, err
}
for _, anime := range response.Data.Shows.Edges {
var episodesStr string
if episodes, ok := anime.AvailableEpisodes.(map[string]interface{}); ok {
if modeEpisodes, ok := episodes[mode].(float64); ok {
episodesStr = fmt.Sprintf("%d", int(modeEpisodes))
} else {
episodesStr = "Unknown"
}
} else {
episodesStr = "Unknown"
}
// Use English name if available and configured, otherwise use default name
displayName := anime.Name
if anime.EnglishName != "" && userCurdConfig != nil && userCurdConfig.AnimeNameLanguage == "english" {
displayName = anime.EnglishName
}
label := fmt.Sprintf("%s (%s episodes)", displayName, episodesStr)
if mode != preferredMode {
label = fmt.Sprintf("%s [%s]", label, mode)
}
animeList = append(animeList, SelectionOption{
Title: displayName,
Key: anime.ID,
Label: label,
Thumbnail: anime.Thumbnail,
})
}
return animeList, nil
}
// Helper function
func min(a, b int) int {
if a < b {
return a
}
return b
}
================================================
FILE: internal/aniskip.go
================================================
package internal
import (
"encoding/json"
"fmt"
"io"
"math"
"net/http"
)
// skipTimesResponse struct to hold the response from the AniSkip API
type skipTimesResponse struct {
Found bool `json:"found"`
Results []skipResult `json:"results"`
}
// skipResult struct to hold individual skip result data
type skipResult struct {
Interval skipInterval `json:"interval"`
}
// skipInterval struct to hold the start and end times for skip intervals
type skipInterval struct {
StartTime float64 `json:"start_time"`
EndTime float64 `json:"end_time"`
}
// GetAniSkipData fetches skip times data for a given anime ID and episode
func GetAniSkipData(animeMalId int, episode int) (string, error) {
baseURL := "https://api.aniskip.com/v1/skip-times"
url := fmt.Sprintf("%s/%d/%d?types=op&types=ed", baseURL, animeMalId, episode)
resp, err := http.Get(url)
if err != nil {
Log(fmt.Errorf("error fetching data from AniSkip API: %w", err))
return "", fmt.Errorf("error fetching data from AniSkip API: %w", err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
Log(fmt.Sprintf("failed with status %d", resp.StatusCode))
return "", fmt.Errorf("failed with status %d", resp.StatusCode)
}
body, err := io.ReadAll(resp.Body)
if err != nil {
Log(fmt.Errorf("failed to read response body %w", err))
return "", fmt.Errorf("failed to read response body %w", err)
}
return string(body), nil
}
// RoundTime rounds a time value to the specified precision
func RoundTime(timeValue float64, precision int) float64 {
multiplier := math.Pow(10, float64(precision))
return math.Floor(timeValue*multiplier+0.5) / multiplier
}
// ParseAniSkipResponse parses the response text from the AniSkip API and updates the Anime struct
func ParseAniSkipResponse(responseText string, anime *Anime, timePrecision int) error {
if responseText == "" {
return fmt.Errorf("response text is empty")
}
var data skipTimesResponse
err := json.Unmarshal([]byte(responseText), &data)
if err != nil {
return fmt.Errorf("error unmarshalling response: %w", err)
}
if !data.Found {
return fmt.Errorf("no skip times found")
}
// Populate skip times for the anime's episode
if len(data.Results) > 0 {
op := data.Results[0].Interval
anime.Ep.SkipTimes.Op = Skip{
Start: int(RoundTime(op.StartTime, timePrecision)),
End: int(RoundTime(op.EndTime, timePrecision)),
}
}
if len(data.Results) > 1 {
ed := data.Results[len(data.Results)-1].Interval
anime.Ep.SkipTimes.Ed = Skip{
Start: int(RoundTime(ed.StartTime, timePrecision)),
End: int(RoundTime(ed.EndTime, timePrecision)),
}
}
return nil
}
// GetAndParseAniSkipData fetches and parses skip times for a given anime ID and episode
func GetAndParseAniSkipData(animeMalId int, episode int, timePrecision int, anime *Anime) error {
responseText, err := GetAniSkipData(animeMalId, episode)
if err != nil {
return err
}
return ParseAniSkipResponse(responseText, anime, timePrecision)
}
// Function to send OP and ED timings to MPV
func SendSkipTimesToMPV(anime *Anime) error {
chapterList := []map[string]interface{}{
{
"title": "Pre-Opening",
"time": 0.0,
"end": float64(anime.Ep.SkipTimes.Op.Start),
},
{
"title": "Opening",
"time": float64(anime.Ep.SkipTimes.Op.Start),
"end": float64(anime.Ep.SkipTimes.Op.End),
},
{
"title": "Main",
"time": float64(anime.Ep.SkipTimes.Op.End),
"end": float64(anime.Ep.SkipTimes.Ed.Start),
},
{
"title": "Ending",
"time": float64(anime.Ep.SkipTimes.Ed.Start),
"end": float64(anime.Ep.SkipTimes.Ed.End),
},
{
"title": "Post-Credits",
"time": float64(anime.Ep.SkipTimes.Ed.End),
},
}
_, err := MPVSendCommand(anime.Ep.Player.SocketPath, []interface{}{
"set_property",
"chapter-list",
chapterList,
})
if err != nil {
return fmt.Errorf("error sending command to MPV: %w", err)
}
return nil
}
================================================
FILE: internal/config.go
================================================
package internal
import (
"bufio"
"context"
"encoding/json"
"fmt"
// "io"
"net/http"
"net/url"
"os"
"path/filepath"
"reflect"
"strconv"
"strings"
"time"
"github.com/pkg/browser"
)
const (
anilistOAuthURL = "https://anilist.co/api/v2/oauth"
anilistClientID = "20686"
anilistClientSecret = "APfx41cOgSQVMvi88v7PbN7g6kzed2ZQRcxmACod"
anilistRedirectURI = "http://localhost:8000/oauth/callback"
anilistServerPort = 8000
)
// AnilistToken represents the OAuth token response from Anilist
type AnilistToken struct {
AccessToken string `json:"access_token"`
TokenType string `json:"token_type"`
ExpiresIn int `json:"expires_in"`
RefreshToken string `json:"refresh_token"`
ExpiresAt time.Time `json:"expires_at"`
}
// CurdConfig struct with field names that match the config keys
type CurdConfig struct {
Player string `config:"Player"`
MpvArgs []string `config:"MpvArgs"`
SubsLanguage string `config:"SubsLanguage"`
SubOrDub string `config:"SubOrDub"`
StoragePath string `config:"StoragePath"`
AnimeNameLanguage string `config:"AnimeNameLanguage"`
MenuOrder string `config:"MenuOrder"`
PercentageToMarkComplete int `config:"PercentageToMarkComplete"`
NextEpisodePrompt bool `config:"NextEpisodePrompt"`
SkipOp bool `config:"SkipOp"`
SkipEd bool `config:"SkipEd"`
SkipFiller bool `config:"SkipFiller"`
ImagePreview bool `config:"ImagePreview"`
SkipRecap bool `config:"SkipRecap"`
RofiSelection bool `config:"RofiSelection"`
CurrentCategory bool `config:"CurrentCategory"`
ScoreOnCompletion bool `config:"ScoreOnCompletion"`
SaveMpvSpeed bool `config:"SaveMpvSpeed"`
AddMissingOptions bool `config:"AddMissingOptions"`
AlternateScreen bool `config:"AlternateScreen"`
DiscordPresence bool `config:"DiscordPresence"`
DiscordClientId string `config:"DiscordClientId"`
Provider string `config:"Provider"`
}
func GetStoragePath() string {
if globalConfig != nil && globalConfig.StoragePath != "" {
return os.ExpandEnv(globalConfig.StoragePath)
}
return filepath.Join(os.ExpandEnv("$HOME"), ".local", "share", "curd")
}
// Default configuration values as a map
func defaultConfigMap() map[string]string {
return map[string]string{
"Player": "mpv",
"MpvArgs": "[]",
"StoragePath": "$HOME/.local/share/curd",
"AnimeNameLanguage": "english",
"SubsLanguage": "english",
"MenuOrder": "CURRENT,ALL,UNTRACKED,UPDATE,CONTINUE_LAST,PROVIDER",
"SubOrDub": "sub",
"PercentageToMarkComplete": "85",
"NextEpisodePrompt": "false",
"SkipOp": "true",
"SkipEd": "true",
"SkipFiller": "true",
"SkipRecap": "true",
"RofiSelection": "false",
"ImagePreview": "false",
"ScoreOnCompletion": "true",
"SaveMpvSpeed": "true",
"AddMissingOptions": "true",
"AlternateScreen": "true",
"DiscordPresence": "true",
"DiscordClientId": "1287457464148820089",
"Provider": "allanime",
}
}
var globalConfig *CurdConfig
func SetGlobalConfig(config *CurdConfig) {
globalConfig = config
}
func GetGlobalConfig() *CurdConfig {
return globalConfig
}
// Helper function to parse string array from config
func parseStringArray(value string) []string {
// Remove brackets and split by comma
value = strings.TrimPrefix(value, "[")
value = strings.TrimSuffix(value, "]")
if value == "" {
return nil
}
// Split by comma and trim spaces and quotes from each element
parts := strings.Split(value, ",")
result := make([]string, 0, len(parts))
for _, part := range parts {
// Trim spaces and quotes
part = strings.TrimSpace(part)
part = strings.Trim(part, "\"")
if part != "" {
result = append(result, part)
}
}
return result
}
var GlobalConfigPath string
// LoadConfig reads or creates the config file, adds missing fields, and returns the populated CurdConfig struct
func LoadConfig(configPath string) (CurdConfig, error) {
configPath = os.ExpandEnv(configPath) // Substitute environment variables like $HOME
GlobalConfigPath = configPath
// Check if config file exists
if _, err := os.Stat(configPath); os.IsNotExist(err) {
// Create the config file with default values if it doesn't exist
CurdOut("Config file not found. Creating default config...")
if err := createDefaultConfig(configPath); err != nil {
return CurdConfig{}, fmt.Errorf("error creating default config file: %v", err)
}
}
// Load the config from file
configMap, err := LoadConfigFromFile(configPath)
if err != nil {
return CurdConfig{}, fmt.Errorf("error loading config file: %v", err)
}
// Check AddMissingOptions setting first
addMissing := true
if val, exists := configMap["AddMissingOptions"]; exists {
addMissing, _ = strconv.ParseBool(val)
}
// Add missing fields to the config map
updated := false
defaultConfigMap := defaultConfigMap()
for key, defaultValue := range defaultConfigMap {
if _, exists := configMap[key]; !exists {
configMap[key] = defaultValue
updated = true
}
}
// Write updated config back to file only if AddMissingOptions is true
if addMissing && updated {
if err := SaveConfigToFile(configPath, configMap); err != nil {
return CurdConfig{}, fmt.Errorf("error saving updated config file: %v", err)
}
}
// Parse string arrays
if mpvArgs, exists := configMap["MpvArgs"]; exists {
configMap["MpvArgs"] = mpvArgs
}
// Populate the CurdConfig struct from the config map
config := PopulateConfig(configMap)
return config, nil
}
// Create a config file with default values in key=value format
// Ensure the directory exists before creating the file
func createDefaultConfig(path string) error {
defaultConfig := defaultConfigMap()
// Ensure the directory exists
dir := filepath.Dir(path)
if err := os.MkdirAll(dir, 0755); err != nil {
return fmt.Errorf("error creating directory: %v", err)
}
file, err := os.Create(path)
if err != nil {
return fmt.Errorf("error creating file: %v", err)
}
defer file.Close()
writer := bufio.NewWriter(file)
for key, value := range defaultConfig {
line := fmt.Sprintf("%s=%s\n", key, value)
if _, err := writer.WriteString(line); err != nil {
return fmt.Errorf("error writing to file: %v", err)
}
}
if err := writer.Flush(); err != nil {
return fmt.Errorf("error flushing writer: %v", err)
}
return nil
}
// authenticateWithBrowser performs OAuth authentication using browser
func authenticateWithBrowser(tokenPath string) (string, error) {
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute)
defer cancel()
// Try to load existing token first
if token, err := loadToken(tokenPath); err == nil && isTokenValid(token) {
return token.AccessToken, nil
}
// Start local server to handle OAuth callback
callbackCh := make(chan string, 1)
errCh := make(chan error, 1)
mux := http.NewServeMux()
srv := &http.Server{
Addr: fmt.Sprintf(":%d", anilistServerPort),
Handler: mux,
}
// Handle OAuth callback - for authorization code grant, code comes in query params
mux.HandleFunc("/oauth/callback", func(w http.ResponseWriter, r *http.Request) {
code := r.URL.Query().Get("code")
errorParam := r.URL.Query().Get("error")
w.Header().Set("Content-Type", "text/html")
if errorParam != "" {
w.WriteHeader(http.StatusBadRequest)
html := fmt.Sprintf(`<!DOCTYPE html>
<html>
<head>
<title>Curd Authentication</title>
<style>
body { font-family: Arial, sans-serif; margin: 50px; text-align: center; background: #1a1a1a; color: white; }
.error { color: #f44336; font-size: 18px; margin-bottom: 20px; }
</style>
</head>
<body>
<div class="error">Authentication failed: %s</div>
<p>You can close this window and try again.</p>
</body>
</html>`, errorParam)
fmt.Fprint(w, html)
errCh <- fmt.Errorf("oauth error: %s", errorParam)
return
}
if code == "" {
w.WriteHeader(http.StatusBadRequest)
html := `<!DOCTYPE html>
<html>
<head>
<title>Curd Authentication</title>
<style>
body { font-family: Arial, sans-serif; margin: 50px; text-align: center; background: #1a1a1a; color: white; }
.error { color: #f44336; font-size: 18px; margin-bottom: 20px; }
</style>
</head>
<body>
<div class="error">No authorization code received</div>
<p>You can close this window and try again.</p>
</body>
</html>`
fmt.Fprint(w, html)
errCh <- fmt.Errorf("no authorization code received")
return
}
// Exchange authorization code for access token
go func() {
tokenURL := fmt.Sprintf("%s/token", anilistOAuthURL)
data := url.Values{
"grant_type": {"authorization_code"},
"client_id": {anilistClientID},
"client_secret": {anilistClientSecret},
"redirect_uri": {anilistRedirectURI},
"code": {code},
}
resp, err := http.PostForm(tokenURL, data)
if err != nil {
errCh <- fmt.Errorf("failed to exchange code for token: %w", err)
return
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
errCh <- fmt.Errorf("token exchange failed with status: %d", resp.StatusCode)
return
}
var tokenResponse struct {
AccessToken string `json:"access_token"`
TokenType string `json:"token_type"`
ExpiresIn int `json:"expires_in"`
}
if err := json.NewDecoder(resp.Body).Decode(&tokenResponse); err != nil {
errCh <- fmt.Errorf("failed to parse token response: %w", err)
return
}
if tokenResponse.AccessToken == "" {
errCh <- fmt.Errorf("no access token in response")
return
}
callbackCh <- tokenResponse.AccessToken
}()
// Show success page immediately
html := `<!DOCTYPE html>
<html>
<head>
<title>Curd Authentication</title>
<style>
body { font-family: Arial, sans-serif; margin: 50px; text-align: center; background: #1a1a1a; color: white; }
.loading { color: #2196F3; font-size: 18px; margin-bottom: 20px; }
</style>
</head>
<body>
<div class="loading">Processing authentication...</div>
<p>Exchanging authorization code for token. You can close this window.</p>
</body>
</html>`
fmt.Fprint(w, html)
})
// Start server in background
go func() {
if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed {
errCh <- fmt.Errorf("failed to start server: %w", err)
}
}()
defer srv.Shutdown(ctx)
// Give server a moment to start
time.Sleep(100 * time.Millisecond)
// Open browser for authentication using Authorization Code Grant flow (response_type=code)
authURL := fmt.Sprintf("%s/authorize?client_id=%s&redirect_uri=%s&response_type=code",
anilistOAuthURL,
anilistClientID,
url.QueryEscape(anilistRedirectURI))
fmt.Println("Opening browser for AniList authentication...")
fmt.Printf("If the browser doesn't open automatically, visit: %s\n", authURL)
if err := browser.OpenURL(authURL); err != nil {
fmt.Printf("Failed to open browser automatically: %v\n", err)
fmt.Println("Please copy and paste the URL above into your browser")
}
// Wait for token
var accessToken string
select {
case accessToken = <-callbackCh:
case err := <-errCh:
return "", fmt.Errorf("authentication failed: %w", err)
case <-ctx.Done():
return "", fmt.Errorf("authentication timeout after 5 minutes")
}
// Create token object and save
token := &AnilistToken{
AccessToken: accessToken,
TokenType: "Bearer",
ExpiresIn: 31536000, // AniList tokens are valid for 1 year
ExpiresAt: time.Now().Add(365 * 24 * time.Hour),
}
// Save token to file
if err := saveToken(tokenPath, token); err != nil {
return "", fmt.Errorf("failed to save token: %w", err)
}
fmt.Println("Authentication successful!")
return token.AccessToken, nil
}
// loadToken loads the token from the token file
func loadToken(tokenPath string) (*AnilistToken, error) {
data, err := os.ReadFile(tokenPath)
if err != nil {
return nil, fmt.Errorf("failed to read token file: %w", err)
}
var token AnilistToken
if err := json.Unmarshal(data, &token); err != nil {
return nil, fmt.Errorf("failed to parse token file: %w", err)
}
return &token, nil
}
// saveToken saves the token to the token file
func saveToken(tokenPath string, token *AnilistToken) error {
// Ensure directory exists
if err := os.MkdirAll(filepath.Dir(tokenPath), 0755); err != nil {
return fmt.Errorf("failed to create directory: %w", err)
}
data, err := json.Marshal(token)
if err != nil {
return fmt.Errorf("failed to marshal token: %w", err)
}
return os.WriteFile(tokenPath, data, 0600)
}
// isTokenValid checks if the token is still valid
func isTokenValid(token *AnilistToken) bool {
return token != nil && token.AccessToken != "" && time.Now().Before(token.ExpiresAt)
}
// GetTokenFromFile loads the token from the token file (supports both old text format and new JSON format)
func GetTokenFromFile(tokenPath string) (string, error) {
data, err := os.ReadFile(tokenPath)
if err != nil {
return "", fmt.Errorf("failed to read token from file: %w", err)
}
// Try to parse as JSON first (new format)
var token AnilistToken
if err := json.Unmarshal(data, &token); err == nil {
// It's JSON format, check if token is valid
if isTokenValid(&token) {
return token.AccessToken, nil
}
return "", fmt.Errorf("token has expired")
}
// Fall back to plain text format (old format)
plainToken := strings.TrimSpace(string(data))
if plainToken == "" {
return "", fmt.Errorf("empty token file")
}
return plainToken, nil
}
func ChangeToken(config *CurdConfig, user *User) {
var err error
tokenPath := filepath.Join(os.ExpandEnv(config.StoragePath), "anilist_token.json")
// Try browser-based OAuth first
fmt.Println("Starting browser-based authentication...")
user.Token, err = authenticateWithBrowser(tokenPath)
if err != nil {
Log("Browser authentication failed: " + err.Error())
fmt.Printf("Browser authentication failed: %v\n", err)
fmt.Println("Falling back to manual token entry...")
// Simple CLI fallback
fmt.Println("Please visit: https://anilist.co/api/v2/oauth/authorize?client_id=20686&response_type=token&redirect_uri=http://localhost:8000/oauth/callback")
fmt.Print("Copy and paste your access token here: ")
fmt.Scanln(&user.Token)
if user.Token == "" {
ExitCurd(fmt.Errorf("no token provided"))
}
// Save the manually entered token as JSON format
token := &AnilistToken{
AccessToken: user.Token,
TokenType: "Bearer",
ExpiresIn: 31536000, // AniList tokens are valid for 1 year
ExpiresAt: time.Now().Add(365 * 24 * time.Hour),
}
if err := saveToken(tokenPath, token); err != nil {
ExitCurd(fmt.Errorf("failed to save token: %w", err))
}
}
if user.Token == "" {
ExitCurd(fmt.Errorf("no token provided"))
}
fmt.Println("Token saved successfully!")
}
// LoadConfigFromFile loads config file from disk into a map (key=value format)
func LoadConfigFromFile(path string) (map[string]string, error) {
file, err := os.Open(path)
if err != nil {
return nil, err
}
defer file.Close()
configMap := make(map[string]string)
scanner := bufio.NewScanner(file)
for scanner.Scan() {
line := strings.TrimSpace(scanner.Text())
if line == "" || strings.HasPrefix(line, "#") {
continue // Skip empty lines and comments
}
parts := strings.SplitN(line, "=", 2)
if len(parts) == 2 {
key := strings.TrimSpace(parts[0])
value := strings.TrimSpace(parts[1])
configMap[key] = value
}
}
if err := scanner.Err(); err != nil {
return nil, err
}
return configMap, nil
}
// SaveConfigToFile saves updated config map to file in key=value format
func SaveConfigToFile(path string, configMap map[string]string) error {
file, err := os.Create(path)
if err != nil {
return err
}
defer file.Close()
writer := bufio.NewWriter(file)
for key, value := range configMap {
line := fmt.Sprintf("%s=%s\n", key, value)
if _, err := writer.WriteString(line); err != nil {
return err
}
}
return writer.Flush()
}
// PopulateConfig populates the CurdConfig struct from a map
func PopulateConfig(configMap map[string]string) CurdConfig {
config := CurdConfig{}
configValue := reflect.ValueOf(&config).Elem()
for i := 0; i < configValue.NumField(); i++ {
field := configValue.Type().Field(i)
tag := field.Tag.Get("config")
if value, exists := configMap[tag]; exists {
fieldValue := configValue.FieldByName(field.Name)
if fieldValue.CanSet() {
switch fieldValue.Kind() {
case reflect.String:
fieldValue.SetString(value)
case reflect.Int:
intVal, _ := strconv.Atoi(value)
fieldValue.SetInt(int64(intVal))
case reflect.Bool:
boolVal, _ := strconv.ParseBool(value)
fieldValue.SetBool(boolVal)
}
}
}
}
// Handle MpvArgs specially
if mpvArgs, exists := configMap["MpvArgs"]; exists {
config.MpvArgs = parseStringArray(mpvArgs)
}
// Validate PercentageToMarkComplete range (0-100)
if config.PercentageToMarkComplete < 0 {
config.PercentageToMarkComplete = 0
} else if config.PercentageToMarkComplete > 100 {
config.PercentageToMarkComplete = 100
}
return config
}
func getOrderedCategories(userCurdConfig *CurdConfig) []SelectionOption {
// Define the default categories and all available labels
defaultOrder := []string{"CURRENT", "ALL", "UNTRACKED", "UPDATE", "CONTINUE_LAST", "PROVIDER"}
availableLabels := map[string]string{
"CURRENT": "Currently Watching",
"ALL": "Show All",
"UNTRACKED": "Untracked Watching",
"UPDATE": "Update (Episode, Status, Score)",
"CONTINUE_LAST": "Continue Last Session",
"PLANNING": "Plan to Watch",
"COMPLETED": "Completed",
"PAUSED": "Paused",
"DROPPED": "Dropped",
"REWATCHING": "Rewatching",
"PROVIDER": "Change Provider",
}
// Create ordered list to store final result
finalOrder := make([]string, 0)
seen := make(map[string]bool)
// If no menu order specified, use default order
if userCurdConfig.MenuOrder == "" {
finalOrder = defaultOrder
} else {
// Only show items explicitly specified by user
menuItems := strings.Split(userCurdConfig.MenuOrder, ",")
for _, key := range menuItems {
key = strings.TrimSpace(key)
if _, exists := availableLabels[key]; exists && !seen[key] {
finalOrder = append(finalOrder, key)
seen[key] = true
}
}
}
// Create the final ordered slice of SelectionOptions
orderedCategories := make([]SelectionOption, 0, len(finalOrder))
for _, key := range finalOrder {
orderedCategories = append(orderedCategories, SelectionOption{
Key: key,
Label: availableLabels[key],
})
}
return orderedCategories
}
================================================
FILE: internal/curd.go
================================================
package internal
import (
"bufio"
"crypto/md5"
"encoding/json"
"fmt"
"io"
"net/http"
"os"
"os/exec"
"path/filepath"
"regexp"
"runtime"
"strconv"
"strings"
"time"
"github.com/gen2brain/beeep"
"github.com/pkg/browser"
)
var alternateScreenActive bool
func EditConfig(configFilePath string) {
// Get the user's preferred editor from the EDITOR environment variable
editor := os.Getenv("EDITOR")
if editor == "" {
// If EDITOR is not set, use system-specific defaults
if runtime.GOOS == "windows" {
// Try Notepad++ first
if _, err := exec.LookPath("notepad++"); err == nil {
editor = "notepad++"
} else {
editor = "notepad.exe"
}
} else {
if _, err := exec.LookPath("vim"); err == nil {
editor = "vim"
} else {
editor = "nano"
}
}
}
// Construct the command to open the config file
cmd := exec.Command(editor, configFilePath)
// Set the command to run in the current terminal
cmd.Stdin = os.Stdin
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
// Run the editor command
err := cmd.Run()
if err != nil {
CurdOut(fmt.Sprintf("Error opening config file: %v", err))
return
}
CurdOut("Config file edited successfully.")
}
// ClearLogFile removes all contents from the specified log file
func ClearLogFile(logFile string) error {
// Open the file with truncate flag to clear its contents
file, err := os.OpenFile(logFile, os.O_WRONLY|os.O_TRUNC, 0666)
if err != nil {
return fmt.Errorf("failed to open log file: %w", err)
}
defer file.Close()
return nil
}
// LogData logs the input data into a specified log file with the format [LOG] time lineNumber: logData
func Log(data interface{}) error {
logFile := GetGlobalLogFile()
// Open or create the log file
file, err := os.OpenFile(logFile, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0666)
if err != nil {
return err
}
defer file.Close()
// Attempt to marshal the data into JSON
jsonData, err := json.Marshal(data)
if err != nil {
return err
}
// Get the caller information
_, filename, lineNumber, ok := runtime.Caller(1) // Caller 1 gives the caller of LogData
if !ok {
return fmt.Errorf("unable to get caller information")
}
// Log the current time and the JSON representation along with caller info
currentTime := time.Now().Format("2006/01/02 15:04:05")
logMessage := fmt.Sprintf("[LOG] %s %s:%d: %s\n", currentTime, filename, lineNumber, jsonData)
_, err = fmt.Fprint(file, logMessage) // Write to the file
if err != nil {
return err
}
return nil
}
// ClearScreen clears the terminal screen and saves the state
func ClearScreen() {
userCurdConfig := GetGlobalConfig()
if userCurdConfig == nil {
return
}
if userCurdConfig.AlternateScreen == false {
return
}
fmt.Print("\033[?1049h") // Switch to alternate screen buffer
fmt.Print("\033[2J") // Clear the entire screen
fmt.Print("\033[H") // Move cursor to the top left
alternateScreenActive = true
}
// RestoreScreen restores the original terminal state
func RestoreScreen() {
if !alternateScreenActive {
return
}
fmt.Print("\033[?1049l") // Switch back to the main screen buffer
alternateScreenActive = false
}
func ExitCurd(err error) {
RestoreScreen()
anime := GetGlobalAnime()
if (anime != nil) && (anime.Ep.Player.SocketPath != "") {
_, err = MPVSendCommand(anime.Ep.Player.SocketPath, []interface{}{"quit"})
if err != nil {
Log("Error closing MPV: " + err.Error())
}
}
CurdOut("Have a great day!")
// If the error is not about the connection refused, print the error
if err != nil && !strings.Contains(err.Error(), "dial unix "+anime.Ep.Player.SocketPath+": connect: connection refused") {
CurdOut(fmt.Sprintf("Error: %v", err))
if runtime.GOOS == "windows" {
fmt.Println("Press Enter to exit")
var wait string
fmt.Scanln(&wait)
os.Exit(1)
} else {
os.Exit(1)
}
}
os.Exit(0)
}
func CurdOut(data interface{}) {
userCurdConfig := GetGlobalConfig()
if userCurdConfig == nil {
userCurdConfig = &CurdConfig{}
}
if !userCurdConfig.RofiSelection {
fmt.Println(fmt.Sprintf("%v", data))
} else {
switch runtime.GOOS {
case "windows":
err := beeep.Notify(
"Curd",
fmt.Sprintf("%v", data),
"",
)
if err != nil {
Log(fmt.Sprintf("Failed to send notification: %v", err))
}
case "linux":
// Check if the input starts with "-i" for image notification
dataStr := fmt.Sprintf("%v", data)
if strings.HasPrefix(dataStr, "-i") && userCurdConfig.ImagePreview && userCurdConfig.RofiSelection {
// Split the string to get image path and message
parts := strings.SplitN(dataStr, " ", 3)
if len(parts) == 3 {
// Remove quotes from the message
message := strings.Trim(parts[2], "\"")
cmd := exec.Command("notify-send",
"-a", "Curd",
"-h", "string:x-canonical-private-synchronous:curd-notification",
"Curd",
"-i", parts[1],
message)
err := cmd.Run()
if err != nil {
Log(fmt.Sprintf("%v", cmd))
Log(fmt.Sprintf("Failed to send notification: %v", err))
}
}
} else {
cmd := exec.Command("notify-send",
"-a", "Curd",
"-h", "string:x-canonical-private-synchronous:curd-notification",
"Curd",
dataStr)
err := cmd.Run()
if err != nil {
Log(fmt.Sprintf("%v", cmd))
Log(fmt.Sprintf("Failed to send notification: %v", err))
}
}
}
}
}
func UpdateAnimeEntry(userCurdConfig *CurdConfig, user *User) {
// Create update options
updateOptions := []SelectionOption{
{Key: "CATEGORY", Label: "Change Anime Category"},
{Key: "PROGRESS", Label: "Change Progress"},
{Key: "SCORE", Label: "Add/Change Score"},
}
// Navigation loop for update option selection
updateOptionLoop:
for {
// Sele
gitextract_bu9ojwvr/
├── .gitattributes
├── .github/
│ ├── ISSUE_TEMPLATE/
│ │ └── bug_report.md
│ └── workflows/
│ ├── ci-cd.yml
│ └── update-aur.yml
├── Build/
│ ├── buildlinux
│ ├── buildlinux-arm64
│ ├── buildlinux-x86_64
│ ├── buildmac
│ ├── buildmac-arm64
│ ├── buildmac-x86_64
│ ├── buildwindows
│ ├── buildwindows-arm64
│ ├── buildwindows-x86_64
│ ├── curd-windows-build.iss
│ ├── release
│ └── requirements.txt
├── LICENSE
├── PKGBUILD
├── README.md
├── VERSION.txt
├── cmd/
│ └── curd/
│ └── main.go
├── flake.nix
├── go.mod
├── go.sum
├── internal/
│ ├── anilist.go
│ ├── anilist_cache.go
│ ├── anime_list.go
│ ├── aniskip.go
│ ├── config.go
│ ├── curd.go
│ ├── discord.go
│ ├── episode_list.go
│ ├── episode_url.go
│ ├── filler_list.go
│ ├── globals.go
│ ├── http_client.go
│ ├── jikan.go
│ ├── links.go
│ ├── localTracking.go
│ ├── player.go
│ ├── provider.go
│ ├── provider_allanime.go
│ ├── provider_animepahe.go
│ ├── rofi.go
│ ├── selection_menu.go
│ ├── structs.go
│ ├── unix_ipc.go
│ └── windows_ipc.go
├── package.nix
├── rofi/
│ ├── contextselect.rasi
│ ├── selectanime.rasi
│ ├── selectanimepreview.rasi
│ └── userinput.rasi
└── vendor/
├── github.com/
│ ├── Microsoft/
│ │ └── go-winio/
│ │ ├── .gitattributes
│ │ ├── .golangci.yml
│ │ ├── CODEOWNERS
│ │ ├── LICENSE
│ │ ├── README.md
│ │ ├── SECURITY.md
│ │ ├── backup.go
│ │ ├── doc.go
│ │ ├── ea.go
│ │ ├── file.go
│ │ ├── fileinfo.go
│ │ ├── hvsock.go
│ │ ├── internal/
│ │ │ ├── fs/
│ │ │ │ ├── doc.go
│ │ │ │ ├── fs.go
│ │ │ │ ├── security.go
│ │ │ │ └── zsyscall_windows.go
│ │ │ ├── socket/
│ │ │ │ ├── rawaddr.go
│ │ │ │ ├── socket.go
│ │ │ │ └── zsyscall_windows.go
│ │ │ └── stringbuffer/
│ │ │ └── wstring.go
│ │ ├── pipe.go
│ │ ├── pkg/
│ │ │ └── guid/
│ │ │ ├── guid.go
│ │ │ ├── guid_nonwindows.go
│ │ │ ├── guid_windows.go
│ │ │ └── variant_string.go
│ │ ├── privilege.go
│ │ ├── reparse.go
│ │ ├── sd.go
│ │ ├── syscall.go
│ │ └── zsyscall_windows.go
│ ├── aymanbagabas/
│ │ └── go-osc52/
│ │ └── v2/
│ │ ├── LICENSE
│ │ ├── README.md
│ │ └── osc52.go
│ ├── charmbracelet/
│ │ ├── bubbletea/
│ │ │ ├── .gitattributes
│ │ │ ├── .golangci-soft.yml
│ │ │ ├── .golangci.yml
│ │ │ ├── .goreleaser.yml
│ │ │ ├── LICENSE
│ │ │ ├── README.md
│ │ │ ├── commands.go
│ │ │ ├── exec.go
│ │ │ ├── focus.go
│ │ │ ├── inputreader_other.go
│ │ │ ├── inputreader_windows.go
│ │ │ ├── key.go
│ │ │ ├── key_other.go
│ │ │ ├── key_sequences.go
│ │ │ ├── key_windows.go
│ │ │ ├── logging.go
│ │ │ ├── mouse.go
│ │ │ ├── nil_renderer.go
│ │ │ ├── options.go
│ │ │ ├── renderer.go
│ │ │ ├── screen.go
│ │ │ ├── signals_unix.go
│ │ │ ├── signals_windows.go
│ │ │ ├── standard_renderer.go
│ │ │ ├── tea.go
│ │ │ ├── tea_init.go
│ │ │ ├── tty.go
│ │ │ ├── tty_unix.go
│ │ │ └── tty_windows.go
│ │ ├── lipgloss/
│ │ │ ├── .golangci-soft.yml
│ │ │ ├── .golangci.yml
│ │ │ ├── .goreleaser.yml
│ │ │ ├── LICENSE
│ │ │ ├── README.md
│ │ │ ├── align.go
│ │ │ ├── ansi_unix.go
│ │ │ ├── ansi_windows.go
│ │ │ ├── borders.go
│ │ │ ├── color.go
│ │ │ ├── get.go
│ │ │ ├── join.go
│ │ │ ├── position.go
│ │ │ ├── renderer.go
│ │ │ ├── runes.go
│ │ │ ├── set.go
│ │ │ ├── size.go
│ │ │ ├── style.go
│ │ │ ├── unset.go
│ │ │ └── whitespace.go
│ │ └── x/
│ │ ├── ansi/
│ │ │ ├── LICENSE
│ │ │ ├── ansi.go
│ │ │ ├── ascii.go
│ │ │ ├── background.go
│ │ │ ├── c0.go
│ │ │ ├── c1.go
│ │ │ ├── charset.go
│ │ │ ├── clipboard.go
│ │ │ ├── color.go
│ │ │ ├── ctrl.go
│ │ │ ├── cursor.go
│ │ │ ├── cwd.go
│ │ │ ├── doc.go
│ │ │ ├── focus.go
│ │ │ ├── graphics.go
│ │ │ ├── hyperlink.go
│ │ │ ├── iterm2.go
│ │ │ ├── keypad.go
│ │ │ ├── kitty/
│ │ │ │ ├── decoder.go
│ │ │ │ ├── encoder.go
│ │ │ │ ├── graphics.go
│ │ │ │ └── options.go
│ │ │ ├── kitty.go
│ │ │ ├── method.go
│ │ │ ├── mode.go
│ │ │ ├── modes.go
│ │ │ ├── mouse.go
│ │ │ ├── notification.go
│ │ │ ├── parser/
│ │ │ │ ├── const.go
│ │ │ │ ├── seq.go
│ │ │ │ └── transition_table.go
│ │ │ ├── parser.go
│ │ │ ├── parser_decode.go
│ │ │ ├── parser_handler.go
│ │ │ ├── parser_sync.go
│ │ │ ├── passthrough.go
│ │ │ ├── paste.go
│ │ │ ├── reset.go
│ │ │ ├── screen.go
│ │ │ ├── sgr.go
│ │ │ ├── status.go
│ │ │ ├── style.go
│ │ │ ├── termcap.go
│ │ │ ├── title.go
│ │ │ ├── truncate.go
│ │ │ ├── util.go
│ │ │ ├── width.go
│ │ │ ├── winop.go
│ │ │ ├── wrap.go
│ │ │ └── xterm.go
│ │ └── term/
│ │ ├── LICENSE
│ │ ├── term.go
│ │ ├── term_other.go
│ │ ├── term_unix.go
│ │ ├── term_unix_bsd.go
│ │ ├── term_unix_other.go
│ │ ├── term_windows.go
│ │ ├── terminal.go
│ │ └── util.go
│ ├── erikgeiser/
│ │ └── coninput/
│ │ ├── .golangci.yml
│ │ ├── LICENSE
│ │ ├── README.md
│ │ ├── keycodes.go
│ │ ├── mode.go
│ │ ├── read.go
│ │ └── records.go
│ ├── gen2brain/
│ │ └── beeep/
│ │ ├── LICENSE
│ │ ├── README.md
│ │ ├── alert_darwin.go
│ │ ├── alert_js.go
│ │ ├── alert_unix.go
│ │ ├── alert_unsupported.go
│ │ ├── alert_windows.go
│ │ ├── beeep.go
│ │ ├── beep_darwin.go
│ │ ├── beep_js.go
│ │ ├── beep_unix.go
│ │ ├── beep_unsupported.go
│ │ ├── beep_windows.go
│ │ ├── notify_darwin.go
│ │ ├── notify_js.go
│ │ ├── notify_unix.go
│ │ ├── notify_unix_nodbus.go
│ │ ├── notify_unsupported.go
│ │ └── notify_windows.go
│ ├── go-rod/
│ │ └── rod/
│ │ ├── .eslintrc.yml
│ │ ├── .golangci.yml
│ │ ├── .prettierrc.yml
│ │ ├── LICENSE
│ │ ├── README.md
│ │ ├── browser.go
│ │ ├── context.go
│ │ ├── dev_helpers.go
│ │ ├── element.go
│ │ ├── error.go
│ │ ├── go.work
│ │ ├── go.work.sum
│ │ ├── hijack.go
│ │ ├── input.go
│ │ ├── lib/
│ │ │ ├── assets/
│ │ │ │ ├── README.md
│ │ │ │ ├── assets.go
│ │ │ │ ├── monitor-page.html
│ │ │ │ └── monitor.html
│ │ │ ├── cdp/
│ │ │ │ ├── README.md
│ │ │ │ ├── client.go
│ │ │ │ ├── error.go
│ │ │ │ ├── format.go
│ │ │ │ ├── utils.go
│ │ │ │ └── websocket.go
│ │ │ ├── defaults/
│ │ │ │ └── defaults.go
│ │ │ ├── devices/
│ │ │ │ ├── device.go
│ │ │ │ ├── list.go
│ │ │ │ └── utils.go
│ │ │ ├── input/
│ │ │ │ ├── README.md
│ │ │ │ ├── keyboard.go
│ │ │ │ ├── keymap.go
│ │ │ │ ├── mac_comands.go
│ │ │ │ └── mouse.go
│ │ │ ├── js/
│ │ │ │ ├── helper.go
│ │ │ │ ├── helper.js
│ │ │ │ └── js.go
│ │ │ ├── launcher/
│ │ │ │ ├── README.md
│ │ │ │ ├── browser.go
│ │ │ │ ├── error.go
│ │ │ │ ├── flags/
│ │ │ │ │ └── flags.go
│ │ │ │ ├── launcher.go
│ │ │ │ ├── manager.go
│ │ │ │ ├── os_unix.go
│ │ │ │ ├── os_windows.go
│ │ │ │ ├── revision.go
│ │ │ │ ├── url_parser.go
│ │ │ │ └── utils.go
│ │ │ ├── proto/
│ │ │ │ ├── README.md
│ │ │ │ ├── a_interface.go
│ │ │ │ ├── a_patch.go
│ │ │ │ ├── a_utils.go
│ │ │ │ ├── accessibility.go
│ │ │ │ ├── animation.go
│ │ │ │ ├── audits.go
│ │ │ │ ├── autofill.go
│ │ │ │ ├── background_service.go
│ │ │ │ ├── browser.go
│ │ │ │ ├── cache_storage.go
│ │ │ │ ├── cast.go
│ │ │ │ ├── console.go
│ │ │ │ ├── css.go
│ │ │ │ ├── database.go
│ │ │ │ ├── debugger.go
│ │ │ │ ├── definitions.go
│ │ │ │ ├── device_access.go
│ │ │ │ ├── device_orientation.go
│ │ │ │ ├── dom.go
│ │ │ │ ├── dom_debugger.go
│ │ │ │ ├── dom_snapshot.go
│ │ │ │ ├── dom_storage.go
│ │ │ │ ├── emulation.go
│ │ │ │ ├── event_breakpoints.go
│ │ │ │ ├── extensions.go
│ │ │ │ ├── fed_cm.go
│ │ │ │ ├── fetch.go
│ │ │ │ ├── headless_experimental.go
│ │ │ │ ├── heap_profiler.go
│ │ │ │ ├── indexed_db.go
│ │ │ │ ├── input.go
│ │ │ │ ├── inspector.go
│ │ │ │ ├── io.go
│ │ │ │ ├── layer_tree.go
│ │ │ │ ├── log.go
│ │ │ │ ├── media.go
│ │ │ │ ├── memory.go
│ │ │ │ ├── network.go
│ │ │ │ ├── overlay.go
│ │ │ │ ├── page.go
│ │ │ │ ├── performance.go
│ │ │ │ ├── performance_timeline.go
│ │ │ │ ├── preload.go
│ │ │ │ ├── profiler.go
│ │ │ │ ├── pwa.go
│ │ │ │ ├── runtime.go
│ │ │ │ ├── schema.go
│ │ │ │ ├── security.go
│ │ │ │ ├── service_worker.go
│ │ │ │ ├── storage.go
│ │ │ │ ├── system_info.go
│ │ │ │ ├── target.go
│ │ │ │ ├── tethering.go
│ │ │ │ ├── tracing.go
│ │ │ │ ├── web_audio.go
│ │ │ │ └── web_authn.go
│ │ │ └── utils/
│ │ │ ├── imageutil.go
│ │ │ ├── sleeper.go
│ │ │ └── utils.go
│ │ ├── must.go
│ │ ├── page.go
│ │ ├── page_eval.go
│ │ ├── query.go
│ │ ├── states.go
│ │ └── utils.go
│ ├── go-toast/
│ │ └── toast/
│ │ ├── LICENSE
│ │ ├── readme.md
│ │ └── toast.go
│ ├── godbus/
│ │ └── dbus/
│ │ └── v5/
│ │ ├── CONTRIBUTING.md
│ │ ├── LICENSE
│ │ ├── MAINTAINERS
│ │ ├── README.md
│ │ ├── auth.go
│ │ ├── auth_anonymous.go
│ │ ├── auth_external.go
│ │ ├── auth_sha1.go
│ │ ├── call.go
│ │ ├── conn.go
│ │ ├── conn_darwin.go
│ │ ├── conn_other.go
│ │ ├── conn_unix.go
│ │ ├── conn_windows.go
│ │ ├── dbus.go
│ │ ├── decoder.go
│ │ ├── default_handler.go
│ │ ├── doc.go
│ │ ├── encoder.go
│ │ ├── escape.go
│ │ ├── export.go
│ │ ├── homedir.go
│ │ ├── match.go
│ │ ├── message.go
│ │ ├── object.go
│ │ ├── sequence.go
│ │ ├── sequential_handler.go
│ │ ├── server_interfaces.go
│ │ ├── sig.go
│ │ ├── transport_darwin.go
│ │ ├── transport_generic.go
│ │ ├── transport_nonce_tcp.go
│ │ ├── transport_tcp.go
│ │ ├── transport_unix.go
│ │ ├── transport_unixcred_dragonfly.go
│ │ ├── transport_unixcred_freebsd.go
│ │ ├── transport_unixcred_linux.go
│ │ ├── transport_unixcred_netbsd.go
│ │ ├── transport_unixcred_openbsd.go
│ │ ├── transport_zos.go
│ │ ├── variant.go
│ │ ├── variant_lexer.go
│ │ └── variant_parser.go
│ ├── lucasb-eyer/
│ │ └── go-colorful/
│ │ ├── CHANGELOG.md
│ │ ├── LICENSE
│ │ ├── README.md
│ │ ├── colorgens.go
│ │ ├── colors.go
│ │ ├── happy_palettegen.go
│ │ ├── hexcolor.go
│ │ ├── hsluv-snapshot-rev4.json
│ │ ├── hsluv.go
│ │ ├── soft_palettegen.go
│ │ └── warm_palettegen.go
│ ├── mattn/
│ │ ├── go-isatty/
│ │ │ ├── LICENSE
│ │ │ ├── README.md
│ │ │ ├── doc.go
│ │ │ ├── go.test.sh
│ │ │ ├── isatty_bsd.go
│ │ │ ├── isatty_others.go
│ │ │ ├── isatty_plan9.go
│ │ │ ├── isatty_solaris.go
│ │ │ ├── isatty_tcgets.go
│ │ │ └── isatty_windows.go
│ │ ├── go-localereader/
│ │ │ ├── README.md
│ │ │ ├── localereader.go
│ │ │ ├── localereader_unix.go
│ │ │ └── localereader_windows.go
│ │ └── go-runewidth/
│ │ ├── LICENSE
│ │ ├── README.md
│ │ ├── runewidth.go
│ │ ├── runewidth_appengine.go
│ │ ├── runewidth_js.go
│ │ ├── runewidth_posix.go
│ │ ├── runewidth_table.go
│ │ └── runewidth_windows.go
│ ├── muesli/
│ │ ├── ansi/
│ │ │ ├── .golangci.yml
│ │ │ ├── LICENSE
│ │ │ ├── README.md
│ │ │ ├── ansi.go
│ │ │ ├── buffer.go
│ │ │ ├── compressor/
│ │ │ │ └── writer.go
│ │ │ └── writer.go
│ │ ├── cancelreader/
│ │ │ ├── .golangci-soft.yml
│ │ │ ├── .golangci.yml
│ │ │ ├── LICENSE
│ │ │ ├── README.md
│ │ │ ├── cancelreader.go
│ │ │ ├── cancelreader_bsd.go
│ │ │ ├── cancelreader_default.go
│ │ │ ├── cancelreader_linux.go
│ │ │ ├── cancelreader_select.go
│ │ │ ├── cancelreader_unix.go
│ │ │ └── cancelreader_windows.go
│ │ └── termenv/
│ │ ├── .golangci-soft.yml
│ │ ├── .golangci.yml
│ │ ├── LICENSE
│ │ ├── README.md
│ │ ├── ansi_compat.md
│ │ ├── ansicolors.go
│ │ ├── color.go
│ │ ├── constants_linux.go
│ │ ├── constants_solaris.go
│ │ ├── constants_unix.go
│ │ ├── copy.go
│ │ ├── hyperlink.go
│ │ ├── notification.go
│ │ ├── output.go
│ │ ├── profile.go
│ │ ├── screen.go
│ │ ├── style.go
│ │ ├── templatehelper.go
│ │ ├── termenv.go
│ │ ├── termenv_other.go
│ │ ├── termenv_posix.go
│ │ ├── termenv_solaris.go
│ │ ├── termenv_unix.go
│ │ └── termenv_windows.go
│ ├── nu7hatch/
│ │ └── gouuid/
│ │ ├── COPYING
│ │ ├── README.md
│ │ └── uuid.go
│ ├── pkg/
│ │ └── browser/
│ │ ├── LICENSE
│ │ ├── README.md
│ │ ├── browser.go
│ │ ├── browser_darwin.go
│ │ ├── browser_freebsd.go
│ │ ├── browser_linux.go
│ │ ├── browser_netbsd.go
│ │ ├── browser_openbsd.go
│ │ ├── browser_unsupported.go
│ │ └── browser_windows.go
│ ├── rivo/
│ │ └── uniseg/
│ │ ├── LICENSE.txt
│ │ ├── README.md
│ │ ├── doc.go
│ │ ├── eastasianwidth.go
│ │ ├── emojipresentation.go
│ │ ├── gen_breaktest.go
│ │ ├── gen_properties.go
│ │ ├── grapheme.go
│ │ ├── graphemeproperties.go
│ │ ├── graphemerules.go
│ │ ├── line.go
│ │ ├── lineproperties.go
│ │ ├── linerules.go
│ │ ├── properties.go
│ │ ├── sentence.go
│ │ ├── sentenceproperties.go
│ │ ├── sentencerules.go
│ │ ├── step.go
│ │ ├── width.go
│ │ ├── word.go
│ │ ├── wordproperties.go
│ │ └── wordrules.go
│ ├── tadvi/
│ │ └── systray/
│ │ ├── AUTHORS
│ │ ├── LICENSE
│ │ ├── README.md
│ │ ├── systray_linux.go
│ │ └── systray_windows.go
│ ├── tr1xem/
│ │ └── go-discordrpc/
│ │ ├── LICENSE
│ │ ├── client/
│ │ │ ├── client.go
│ │ │ ├── inputMapper.go
│ │ │ └── types.go
│ │ └── internal/
│ │ └── ipc/
│ │ ├── ipc.go
│ │ ├── ipc_unix.go
│ │ └── ipc_windows.go
│ └── ysmood/
│ ├── fetchup/
│ │ ├── LICENSE
│ │ ├── README.md
│ │ ├── download.go
│ │ ├── events.go
│ │ ├── fetchup.go
│ │ └── utils.go
│ ├── goob/
│ │ ├── .golangci.yml
│ │ ├── LICENSE
│ │ ├── goob.go
│ │ ├── pipe.go
│ │ └── readme.md
│ ├── got/
│ │ ├── LICENSE
│ │ └── lib/
│ │ └── lcs/
│ │ ├── lcs.go
│ │ ├── sequence.go
│ │ └── utils.go
│ ├── gson/
│ │ ├── LICENSE
│ │ ├── README.md
│ │ ├── read.go
│ │ └── write.go
│ └── leakless/
│ ├── .golangci.yml
│ ├── LICENSE
│ ├── bin_amd64_darwin.go
│ ├── bin_amd64_linux.go
│ ├── bin_amd64_windows.go
│ ├── bin_arm64_darwin.go
│ ├── bin_arm64_linux.go
│ ├── leakless.go
│ ├── pkg/
│ │ ├── shared/
│ │ │ ├── message.go
│ │ │ └── version.go
│ │ └── utils/
│ │ ├── target.go
│ │ └── utils.go
│ └── readme.md
├── golang.org/
│ └── x/
│ ├── sync/
│ │ ├── LICENSE
│ │ ├── PATENTS
│ │ └── errgroup/
│ │ ├── errgroup.go
│ │ ├── go120.go
│ │ └── pre_go120.go
│ ├── sys/
│ │ ├── LICENSE
│ │ ├── PATENTS
│ │ ├── unix/
│ │ │ ├── README.md
│ │ │ ├── affinity_linux.go
│ │ │ ├── aliases.go
│ │ │ ├── asm_aix_ppc64.s
│ │ │ ├── asm_bsd_386.s
│ │ │ ├── asm_bsd_amd64.s
│ │ │ ├── asm_bsd_arm.s
│ │ │ ├── asm_bsd_arm64.s
│ │ │ ├── asm_bsd_ppc64.s
│ │ │ ├── asm_bsd_riscv64.s
│ │ │ ├── asm_linux_386.s
│ │ │ ├── asm_linux_amd64.s
│ │ │ ├── asm_linux_arm.s
│ │ │ ├── asm_linux_arm64.s
│ │ │ ├── asm_linux_loong64.s
│ │ │ ├── asm_linux_mips64x.s
│ │ │ ├── asm_linux_mipsx.s
│ │ │ ├── asm_linux_ppc64x.s
│ │ │ ├── asm_linux_riscv64.s
│ │ │ ├── asm_linux_s390x.s
│ │ │ ├── asm_openbsd_mips64.s
│ │ │ ├── asm_solaris_amd64.s
│ │ │ ├── asm_zos_s390x.s
│ │ │ ├── auxv.go
│ │ │ ├── auxv_unsupported.go
│ │ │ ├── bluetooth_linux.go
│ │ │ ├── bpxsvc_zos.go
│ │ │ ├── bpxsvc_zos.s
│ │ │ ├── cap_freebsd.go
│ │ │ ├── constants.go
│ │ │ ├── dev_aix_ppc.go
│ │ │ ├── dev_aix_ppc64.go
│ │ │ ├── dev_darwin.go
│ │ │ ├── dev_dragonfly.go
│ │ │ ├── dev_freebsd.go
│ │ │ ├── dev_linux.go
│ │ │ ├── dev_netbsd.go
│ │ │ ├── dev_openbsd.go
│ │ │ ├── dev_zos.go
│ │ │ ├── dirent.go
│ │ │ ├── endian_big.go
│ │ │ ├── endian_little.go
│ │ │ ├── env_unix.go
│ │ │ ├── fcntl.go
│ │ │ ├── fcntl_darwin.go
│ │ │ ├── fcntl_linux_32bit.go
│ │ │ ├── fdset.go
│ │ │ ├── gccgo.go
│ │ │ ├── gccgo_c.c
│ │ │ ├── gccgo_linux_amd64.go
│ │ │ ├── ifreq_linux.go
│ │ │ ├── ioctl_linux.go
│ │ │ ├── ioctl_signed.go
│ │ │ ├── ioctl_unsigned.go
│ │ │ ├── ioctl_zos.go
│ │ │ ├── mkall.sh
│ │ │ ├── mkerrors.sh
│ │ │ ├── mmap_nomremap.go
│ │ │ ├── mremap.go
│ │ │ ├── pagesize_unix.go
│ │ │ ├── pledge_openbsd.go
│ │ │ ├── ptrace_darwin.go
│ │ │ ├── ptrace_ios.go
│ │ │ ├── race.go
│ │ │ ├── race0.go
│ │ │ ├── readdirent_getdents.go
│ │ │ ├── readdirent_getdirentries.go
│ │ │ ├── sockcmsg_dragonfly.go
│ │ │ ├── sockcmsg_linux.go
│ │ │ ├── sockcmsg_unix.go
│ │ │ ├── sockcmsg_unix_other.go
│ │ │ ├── sockcmsg_zos.go
│ │ │ ├── symaddr_zos_s390x.s
│ │ │ ├── syscall.go
│ │ │ ├── syscall_aix.go
│ │ │ ├── syscall_aix_ppc.go
│ │ │ ├── syscall_aix_ppc64.go
│ │ │ ├── syscall_bsd.go
│ │ │ ├── syscall_darwin.go
│ │ │ ├── syscall_darwin_amd64.go
│ │ │ ├── syscall_darwin_arm64.go
│ │ │ ├── syscall_darwin_libSystem.go
│ │ │ ├── syscall_dragonfly.go
│ │ │ ├── syscall_dragonfly_amd64.go
│ │ │ ├── syscall_freebsd.go
│ │ │ ├── syscall_freebsd_386.go
│ │ │ ├── syscall_freebsd_amd64.go
│ │ │ ├── syscall_freebsd_arm.go
│ │ │ ├── syscall_freebsd_arm64.go
│ │ │ ├── syscall_freebsd_riscv64.go
│ │ │ ├── syscall_hurd.go
│ │ │ ├── syscall_hurd_386.go
│ │ │ ├── syscall_illumos.go
│ │ │ ├── syscall_linux.go
│ │ │ ├── syscall_linux_386.go
│ │ │ ├── syscall_linux_alarm.go
│ │ │ ├── syscall_linux_amd64.go
│ │ │ ├── syscall_linux_amd64_gc.go
│ │ │ ├── syscall_linux_arm.go
│ │ │ ├── syscall_linux_arm64.go
│ │ │ ├── syscall_linux_gc.go
│ │ │ ├── syscall_linux_gc_386.go
│ │ │ ├── syscall_linux_gc_arm.go
│ │ │ ├── syscall_linux_gccgo_386.go
│ │ │ ├── syscall_linux_gccgo_arm.go
│ │ │ ├── syscall_linux_loong64.go
│ │ │ ├── syscall_linux_mips64x.go
│ │ │ ├── syscall_linux_mipsx.go
│ │ │ ├── syscall_linux_ppc.go
│ │ │ ├── syscall_linux_ppc64x.go
│ │ │ ├── syscall_linux_riscv64.go
│ │ │ ├── syscall_linux_s390x.go
│ │ │ ├── syscall_linux_sparc64.go
│ │ │ ├── syscall_netbsd.go
│ │ │ ├── syscall_netbsd_386.go
│ │ │ ├── syscall_netbsd_amd64.go
│ │ │ ├── syscall_netbsd_arm.go
│ │ │ ├── syscall_netbsd_arm64.go
│ │ │ ├── syscall_openbsd.go
│ │ │ ├── syscall_openbsd_386.go
│ │ │ ├── syscall_openbsd_amd64.go
│ │ │ ├── syscall_openbsd_arm.go
│ │ │ ├── syscall_openbsd_arm64.go
│ │ │ ├── syscall_openbsd_libc.go
│ │ │ ├── syscall_openbsd_mips64.go
│ │ │ ├── syscall_openbsd_ppc64.go
│ │ │ ├── syscall_openbsd_riscv64.go
│ │ │ ├── syscall_solaris.go
│ │ │ ├── syscall_solaris_amd64.go
│ │ │ ├── syscall_unix.go
│ │ │ ├── syscall_unix_gc.go
│ │ │ ├── syscall_unix_gc_ppc64x.go
│ │ │ ├── syscall_zos_s390x.go
│ │ │ ├── sysvshm_linux.go
│ │ │ ├── sysvshm_unix.go
│ │ │ ├── sysvshm_unix_other.go
│ │ │ ├── timestruct.go
│ │ │ ├── unveil_openbsd.go
│ │ │ ├── vgetrandom_linux.go
│ │ │ ├── vgetrandom_unsupported.go
│ │ │ ├── xattr_bsd.go
│ │ │ ├── zerrors_aix_ppc.go
│ │ │ ├── zerrors_aix_ppc64.go
│ │ │ ├── zerrors_darwin_amd64.go
│ │ │ ├── zerrors_darwin_arm64.go
│ │ │ ├── zerrors_dragonfly_amd64.go
│ │ │ ├── zerrors_freebsd_386.go
│ │ │ ├── zerrors_freebsd_amd64.go
│ │ │ ├── zerrors_freebsd_arm.go
│ │ │ ├── zerrors_freebsd_arm64.go
│ │ │ ├── zerrors_freebsd_riscv64.go
│ │ │ ├── zerrors_linux.go
│ │ │ ├── zerrors_linux_386.go
│ │ │ ├── zerrors_linux_amd64.go
│ │ │ ├── zerrors_linux_arm.go
│ │ │ ├── zerrors_linux_arm64.go
│ │ │ ├── zerrors_linux_loong64.go
│ │ │ ├── zerrors_linux_mips.go
│ │ │ ├── zerrors_linux_mips64.go
│ │ │ ├── zerrors_linux_mips64le.go
│ │ │ ├── zerrors_linux_mipsle.go
│ │ │ ├── zerrors_linux_ppc.go
│ │ │ ├── zerrors_linux_ppc64.go
│ │ │ ├── zerrors_linux_ppc64le.go
│ │ │ ├── zerrors_linux_riscv64.go
│ │ │ ├── zerrors_linux_s390x.go
│ │ │ ├── zerrors_linux_sparc64.go
│ │ │ ├── zerrors_netbsd_386.go
│ │ │ ├── zerrors_netbsd_amd64.go
│ │ │ ├── zerrors_netbsd_arm.go
│ │ │ ├── zerrors_netbsd_arm64.go
│ │ │ ├── zerrors_openbsd_386.go
│ │ │ ├── zerrors_openbsd_amd64.go
│ │ │ ├── zerrors_openbsd_arm.go
│ │ │ ├── zerrors_openbsd_arm64.go
│ │ │ ├── zerrors_openbsd_mips64.go
│ │ │ ├── zerrors_openbsd_ppc64.go
│ │ │ ├── zerrors_openbsd_riscv64.go
│ │ │ ├── zerrors_solaris_amd64.go
│ │ │ ├── zerrors_zos_s390x.go
│ │ │ ├── zptrace_armnn_linux.go
│ │ │ ├── zptrace_linux_arm64.go
│ │ │ ├── zptrace_mipsnn_linux.go
│ │ │ ├── zptrace_mipsnnle_linux.go
│ │ │ ├── zptrace_x86_linux.go
│ │ │ ├── zsymaddr_zos_s390x.s
│ │ │ ├── zsyscall_aix_ppc.go
│ │ │ ├── zsyscall_aix_ppc64.go
│ │ │ ├── zsyscall_aix_ppc64_gc.go
│ │ │ ├── zsyscall_aix_ppc64_gccgo.go
│ │ │ ├── zsyscall_darwin_amd64.go
│ │ │ ├── zsyscall_darwin_amd64.s
│ │ │ ├── zsyscall_darwin_arm64.go
│ │ │ ├── zsyscall_darwin_arm64.s
│ │ │ ├── zsyscall_dragonfly_amd64.go
│ │ │ ├── zsyscall_freebsd_386.go
│ │ │ ├── zsyscall_freebsd_amd64.go
│ │ │ ├── zsyscall_freebsd_arm.go
│ │ │ ├── zsyscall_freebsd_arm64.go
│ │ │ ├── zsyscall_freebsd_riscv64.go
│ │ │ ├── zsyscall_illumos_amd64.go
│ │ │ ├── zsyscall_linux.go
│ │ │ ├── zsyscall_linux_386.go
│ │ │ ├── zsyscall_linux_amd64.go
│ │ │ ├── zsyscall_linux_arm.go
│ │ │ ├── zsyscall_linux_arm64.go
│ │ │ ├── zsyscall_linux_loong64.go
│ │ │ ├── zsyscall_linux_mips.go
│ │ │ ├── zsyscall_linux_mips64.go
│ │ │ ├── zsyscall_linux_mips64le.go
│ │ │ ├── zsyscall_linux_mipsle.go
│ │ │ ├── zsyscall_linux_ppc.go
│ │ │ ├── zsyscall_linux_ppc64.go
│ │ │ ├── zsyscall_linux_ppc64le.go
│ │ │ ├── zsyscall_linux_riscv64.go
│ │ │ ├── zsyscall_linux_s390x.go
│ │ │ ├── zsyscall_linux_sparc64.go
│ │ │ ├── zsyscall_netbsd_386.go
│ │ │ ├── zsyscall_netbsd_amd64.go
│ │ │ ├── zsyscall_netbsd_arm.go
│ │ │ ├── zsyscall_netbsd_arm64.go
│ │ │ ├── zsyscall_openbsd_386.go
│ │ │ ├── zsyscall_openbsd_386.s
│ │ │ ├── zsyscall_openbsd_amd64.go
│ │ │ ├── zsyscall_openbsd_amd64.s
│ │ │ ├── zsyscall_openbsd_arm.go
│ │ │ ├── zsyscall_openbsd_arm.s
│ │ │ ├── zsyscall_openbsd_arm64.go
│ │ │ ├── zsyscall_openbsd_arm64.s
│ │ │ ├── zsyscall_openbsd_mips64.go
│ │ │ ├── zsyscall_openbsd_mips64.s
│ │ │ ├── zsyscall_openbsd_ppc64.go
│ │ │ ├── zsyscall_openbsd_ppc64.s
│ │ │ ├── zsyscall_openbsd_riscv64.go
│ │ │ ├── zsyscall_openbsd_riscv64.s
│ │ │ ├── zsyscall_solaris_amd64.go
│ │ │ ├── zsyscall_zos_s390x.go
│ │ │ ├── zsysctl_openbsd_386.go
│ │ │ ├── zsysctl_openbsd_amd64.go
│ │ │ ├── zsysctl_openbsd_arm.go
│ │ │ ├── zsysctl_openbsd_arm64.go
│ │ │ ├── zsysctl_openbsd_mips64.go
│ │ │ ├── zsysctl_openbsd_ppc64.go
│ │ │ ├── zsysctl_openbsd_riscv64.go
│ │ │ ├── zsysnum_darwin_amd64.go
│ │ │ ├── zsysnum_darwin_arm64.go
│ │ │ ├── zsysnum_dragonfly_amd64.go
│ │ │ ├── zsysnum_freebsd_386.go
│ │ │ ├── zsysnum_freebsd_amd64.go
│ │ │ ├── zsysnum_freebsd_arm.go
│ │ │ ├── zsysnum_freebsd_arm64.go
│ │ │ ├── zsysnum_freebsd_riscv64.go
│ │ │ ├── zsysnum_linux_386.go
│ │ │ ├── zsysnum_linux_amd64.go
│ │ │ ├── zsysnum_linux_arm.go
│ │ │ ├── zsysnum_linux_arm64.go
│ │ │ ├── zsysnum_linux_loong64.go
│ │ │ ├── zsysnum_linux_mips.go
│ │ │ ├── zsysnum_linux_mips64.go
│ │ │ ├── zsysnum_linux_mips64le.go
│ │ │ ├── zsysnum_linux_mipsle.go
│ │ │ ├── zsysnum_linux_ppc.go
│ │ │ ├── zsysnum_linux_ppc64.go
│ │ │ ├── zsysnum_linux_ppc64le.go
│ │ │ ├── zsysnum_linux_riscv64.go
│ │ │ ├── zsysnum_linux_s390x.go
│ │ │ ├── zsysnum_linux_sparc64.go
│ │ │ ├── zsysnum_netbsd_386.go
│ │ │ ├── zsysnum_netbsd_amd64.go
│ │ │ ├── zsysnum_netbsd_arm.go
│ │ │ ├── zsysnum_netbsd_arm64.go
│ │ │ ├── zsysnum_openbsd_386.go
│ │ │ ├── zsysnum_openbsd_amd64.go
│ │ │ ├── zsysnum_openbsd_arm.go
│ │ │ ├── zsysnum_openbsd_arm64.go
│ │ │ ├── zsysnum_openbsd_mips64.go
│ │ │ ├── zsysnum_openbsd_ppc64.go
│ │ │ ├── zsysnum_openbsd_riscv64.go
│ │ │ ├── zsysnum_zos_s390x.go
│ │ │ ├── ztypes_aix_ppc.go
│ │ │ ├── ztypes_aix_ppc64.go
│ │ │ ├── ztypes_darwin_amd64.go
│ │ │ ├── ztypes_darwin_arm64.go
│ │ │ ├── ztypes_dragonfly_amd64.go
│ │ │ ├── ztypes_freebsd_386.go
│ │ │ ├── ztypes_freebsd_amd64.go
│ │ │ ├── ztypes_freebsd_arm.go
│ │ │ ├── ztypes_freebsd_arm64.go
│ │ │ ├── ztypes_freebsd_riscv64.go
│ │ │ ├── ztypes_linux.go
│ │ │ ├── ztypes_linux_386.go
│ │ │ ├── ztypes_linux_amd64.go
│ │ │ ├── ztypes_linux_arm.go
│ │ │ ├── ztypes_linux_arm64.go
│ │ │ ├── ztypes_linux_loong64.go
│ │ │ ├── ztypes_linux_mips.go
│ │ │ ├── ztypes_linux_mips64.go
│ │ │ ├── ztypes_linux_mips64le.go
│ │ │ ├── ztypes_linux_mipsle.go
│ │ │ ├── ztypes_linux_ppc.go
│ │ │ ├── ztypes_linux_ppc64.go
│ │ │ ├── ztypes_linux_ppc64le.go
│ │ │ ├── ztypes_linux_riscv64.go
│ │ │ ├── ztypes_linux_s390x.go
│ │ │ ├── ztypes_linux_sparc64.go
│ │ │ ├── ztypes_netbsd_386.go
│ │ │ ├── ztypes_netbsd_amd64.go
│ │ │ ├── ztypes_netbsd_arm.go
│ │ │ ├── ztypes_netbsd_arm64.go
│ │ │ ├── ztypes_openbsd_386.go
│ │ │ ├── ztypes_openbsd_amd64.go
│ │ │ ├── ztypes_openbsd_arm.go
│ │ │ ├── ztypes_openbsd_arm64.go
│ │ │ ├── ztypes_openbsd_mips64.go
│ │ │ ├── ztypes_openbsd_ppc64.go
│ │ │ ├── ztypes_openbsd_riscv64.go
│ │ │ ├── ztypes_solaris_amd64.go
│ │ │ └── ztypes_zos_s390x.go
│ │ └── windows/
│ │ ├── aliases.go
│ │ ├── dll_windows.go
│ │ ├── env_windows.go
│ │ ├── eventlog.go
│ │ ├── exec_windows.go
│ │ ├── memory_windows.go
│ │ ├── mkerrors.bash
│ │ ├── mkknownfolderids.bash
│ │ ├── mksyscall.go
│ │ ├── race.go
│ │ ├── race0.go
│ │ ├── registry/
│ │ │ ├── key.go
│ │ │ ├── mksyscall.go
│ │ │ ├── syscall.go
│ │ │ ├── value.go
│ │ │ └── zsyscall_windows.go
│ │ ├── security_windows.go
│ │ ├── service.go
│ │ ├── setupapi_windows.go
│ │ ├── str.go
│ │ ├── syscall.go
│ │ ├── syscall_windows.go
│ │ ├── types_windows.go
│ │ ├── types_windows_386.go
│ │ ├── types_windows_amd64.go
│ │ ├── types_windows_arm.go
│ │ ├── types_windows_arm64.go
│ │ ├── zerrors_windows.go
│ │ ├── zknownfolderids_windows.go
│ │ └── zsyscall_windows.go
│ └── text/
│ ├── LICENSE
│ ├── PATENTS
│ └── transform/
│ └── transform.go
├── gopkg.in/
│ └── natefinch/
│ └── npipe.v2/
│ ├── LICENSE.txt
│ ├── README.md
│ ├── doc.go
│ ├── npipe_windows.go
│ ├── znpipe_windows_386.go
│ └── znpipe_windows_amd64.go
└── modules.txt
Showing preview only (8,990K chars total). Download the full file or copy to clipboard to get everything.
SYMBOL INDEX (105600 symbols across 708 files)
FILE: cmd/curd/main.go
function resolvedVersion (line 18) | func resolvedVersion() string {
function main (line 26) | func main() {
FILE: internal/anilist.go
function FindKeyByValue (line 17) | func FindKeyByValue(m map[string]string, value string) (string, error) {
function GetAnimeMap (line 27) | func GetAnimeMap(animeList AnimeList) map[string]string {
function GetAnimeMapPreview (line 56) | func GetAnimeMapPreview(animeList AnimeList) map[string]RofiSelectPreview {
function levenshtein (line 92) | func levenshtein(a, b string) int {
function min3 (line 129) | func min3(a, b, c int) int {
function SearchAnimeAnilistPreview (line 140) | func SearchAnimeAnilistPreview(query, token string) (map[string]RofiSele...
function SearchAnimeAnilist (line 236) | func SearchAnimeAnilist(query, token string) ([]SelectionOption, error) {
function GetAnilistUserID (line 327) | func GetAnilistUserID(token string) (int, string, error) {
function AddAnimeToWatchingList (line 356) | func AddAnimeToWatchingList(animeID int, token string) error {
function GetAnimeMalID (line 385) | func GetAnimeMalID(anilistMediaID int) (int, error) {
function GetAnimeIDAndImage (line 408) | func GetAnimeIDAndImage(anilistMediaID int) (int, string, error) {
function GetUserData (line 437) | func GetUserData(token string, userID int) (map[string]interface{}, erro...
function GetUserDataPreview (line 491) | func GetUserDataPreview(token string, userID int) (map[string]interface{...
function LoadJSONFile (line 549) | func LoadJSONFile(filePath string) (map[string]interface{}, error) {
function SearchAnimeByTitle (line 565) | func SearchAnimeByTitle(jsonData map[string]interface{}, searchTitle str...
function UpdateAnimeProgress (line 596) | func UpdateAnimeProgress(token string, mediaID, progress int) error {
function UpdateAnimeStatus (line 606) | func UpdateAnimeStatus(token string, mediaID int, status string) error {
function SaveAnimeListEntry (line 625) | func SaveAnimeListEntry(token string, mediaID int, status *string, progr...
function CompleteAnimeRewatch (line 700) | func CompleteAnimeRewatch(token string, anime Anime) error {
function RateAnime (line 707) | func RateAnime(token string, mediaID int) error {
function makePostRequest (line 760) | func makePostRequest(url, query string, variables map[string]interface{}...
function ParseAnimeList (line 805) | func ParseAnimeList(input map[string]interface{}) AnimeList {
function FindAnimeByAnilistID (line 908) | func FindAnimeByAnilistID(list AnimeList, idStr string) (*Entry, error) {
function FindAnimeByAnilistIDInAnimes (line 937) | func FindAnimeByAnilistIDInAnimes(animes []Anime, anilistID int) (*Anime...
function GetAnimeDataByID (line 947) | func GetAnimeDataByID(id int, token string) (Anime, error) {
type SequelInfo (line 1009) | type SequelInfo struct
function GetAnimeSequel (line 1020) | func GetAnimeSequel(animeID int, token string) ([]SequelInfo, error) {
function AddAnimeToList (line 1149) | func AddAnimeToList(animeID int, status string, token string) error {
function FindSequelInAnimeList (line 1188) | func FindSequelInAnimeList(list AnimeList, sequelID int) (string, bool) {
FILE: internal/anilist_cache.go
constant animeListCacheFileName (line 13) | animeListCacheFileName = "anilist_list_cache.json"
type animeListCachePayload (line 15) | type animeListCachePayload struct
type AnimeListSync (line 21) | type AnimeListSync struct
method MarkRefreshDone (line 38) | func (s *AnimeListSync) MarkRefreshDone() {
method RefreshDone (line 43) | func (s *AnimeListSync) RefreshDone() <-chan struct{} {
method Current (line 47) | func (s *AnimeListSync) Current() AnimeList {
method Replace (line 53) | func (s *AnimeListSync) Replace(list AnimeList, notify bool) bool {
method Updates (line 74) | func (s *AnimeListSync) Updates() <-chan AnimeList {
function NewAnimeListSync (line 29) | func NewAnimeListSync(initial AnimeList) *AnimeListSync {
function animeListCachePath (line 78) | func animeListCachePath(storagePath string) string {
function loadAnimeListCache (line 82) | func loadAnimeListCache(storagePath string, userID int) (animeListCacheP...
function saveAnimeListCache (line 101) | func saveAnimeListCache(storagePath string, userID int, list AnimeList) ...
function animeListEqual (line 132) | func animeListEqual(a, b AnimeList) bool {
function FetchLatestAnimeList (line 144) | func FetchLatestAnimeList(token string, userID int) (AnimeList, error) {
function refreshAnimeListInBackground (line 153) | func refreshAnimeListInBackground(userCurdConfig *CurdConfig, user *User) {
function InitializeUserAnimeList (line 190) | func InitializeUserAnimeList(userCurdConfig *CurdConfig, user *User) err...
function RefreshUserAnimeList (line 234) | func RefreshUserAnimeList(userCurdConfig *CurdConfig, user *User) error {
function buildCategorySelectionOptions (line 265) | func buildCategorySelectionOptions(list AnimeList, category string) []Se...
function buildCategoryPreviewOptions (line 284) | func buildCategoryPreviewOptions(list AnimeList, category string) map[st...
FILE: internal/anime_list.go
type anime (line 13) | type anime struct
type response (line 21) | type response struct
function normalizeTranslationType (line 29) | func normalizeTranslationType(mode string) string {
function alternateTranslationType (line 36) | func alternateTranslationType(mode string) string {
function searchAllAnime (line 58) | func searchAllAnime(query, mode string) ([]SelectionOption, error) {
function searchAnimeByMode (line 94) | func searchAnimeByMode(query, mode, preferredMode string) ([]SelectionOp...
function min (line 216) | func min(a, b int) int {
FILE: internal/aniskip.go
type skipTimesResponse (line 12) | type skipTimesResponse struct
type skipResult (line 18) | type skipResult struct
type skipInterval (line 23) | type skipInterval struct
function GetAniSkipData (line 29) | func GetAniSkipData(animeMalId int, episode int) (string, error) {
function RoundTime (line 55) | func RoundTime(timeValue float64, precision int) float64 {
function ParseAniSkipResponse (line 61) | func ParseAniSkipResponse(responseText string, anime *Anime, timePrecisi...
function GetAndParseAniSkipData (line 97) | func GetAndParseAniSkipData(animeMalId int, episode int, timePrecision i...
function SendSkipTimesToMPV (line 106) | func SendSkipTimesToMPV(anime *Anime) error {
FILE: internal/config.go
constant anilistOAuthURL (line 23) | anilistOAuthURL = "https://anilist.co/api/v2/oauth"
constant anilistClientID (line 24) | anilistClientID = "20686"
constant anilistClientSecret (line 25) | anilistClientSecret = "APfx41cOgSQVMvi88v7PbN7g6kzed2ZQRcxmACod"
constant anilistRedirectURI (line 26) | anilistRedirectURI = "http://localhost:8000/oauth/callback"
constant anilistServerPort (line 27) | anilistServerPort = 8000
type AnilistToken (line 31) | type AnilistToken struct
type CurdConfig (line 40) | type CurdConfig struct
function GetStoragePath (line 66) | func GetStoragePath() string {
function defaultConfigMap (line 74) | func defaultConfigMap() map[string]string {
function SetGlobalConfig (line 103) | func SetGlobalConfig(config *CurdConfig) {
function GetGlobalConfig (line 107) | func GetGlobalConfig() *CurdConfig {
function parseStringArray (line 112) | func parseStringArray(value string) []string {
function LoadConfig (line 137) | func LoadConfig(configPath string) (CurdConfig, error) {
function createDefaultConfig (line 192) | func createDefaultConfig(path string) error {
function authenticateWithBrowser (line 221) | func authenticateWithBrowser(tokenPath string) (string, error) {
function loadToken (line 401) | func loadToken(tokenPath string) (*AnilistToken, error) {
function saveToken (line 416) | func saveToken(tokenPath string, token *AnilistToken) error {
function isTokenValid (line 431) | func isTokenValid(token *AnilistToken) bool {
function GetTokenFromFile (line 436) | func GetTokenFromFile(tokenPath string) (string, error) {
function ChangeToken (line 461) | func ChangeToken(config *CurdConfig, user *User) {
function LoadConfigFromFile (line 504) | func LoadConfigFromFile(path string) (map[string]string, error) {
function SaveConfigToFile (line 536) | func SaveConfigToFile(path string, configMap map[string]string) error {
function PopulateConfig (line 554) | func PopulateConfig(configMap map[string]string) CurdConfig {
function getOrderedCategories (line 595) | func getOrderedCategories(userCurdConfig *CurdConfig) []SelectionOption {
FILE: internal/curd.go
function EditConfig (line 25) | func EditConfig(configFilePath string) {
function ClearLogFile (line 65) | func ClearLogFile(logFile string) error {
function Log (line 77) | func Log(data interface{}) error {
function ClearScreen (line 110) | func ClearScreen() {
function RestoreScreen (line 127) | func RestoreScreen() {
function ExitCurd (line 136) | func ExitCurd(err error) {
function CurdOut (line 163) | func CurdOut(data interface{}) {
function UpdateAnimeEntry (line 219) | func UpdateAnimeEntry(userCurdConfig *CurdConfig, user *User) {
function UpdateCurd (line 417) | func UpdateCurd(repo, fileName string) error {
function AddNewAnime (line 518) | func AddNewAnime(userCurdConfig *CurdConfig, anime *Anime, user *User, d...
function SetupCurd (line 619) | func SetupCurd(userCurdConfig *CurdConfig, anime *Anime, user *User, dat...
function WriteTokenToFile (line 1375) | func WriteTokenToFile(token string, filePath string) error {
function StartCurd (line 1393) | func StartCurd(userCurdConfig *CurdConfig, anime *Anime) string {
function CheckAndDownloadFiles (line 1520) | func CheckAndDownloadFiles(storagePath string, filesToCheck []string) er...
function getEntriesByCategory (line 1562) | func getEntriesByCategory(list AnimeList, category string) []Entry {
function NextEpisodePromptCLI (line 1594) | func NextEpisodePromptCLI(userCurdConfig *CurdConfig) bool {
function NextEpisodePromptContinuous (line 1626) | func NextEpisodePromptContinuous(userCurdConfig *CurdConfig, databaseFil...
function NextEpisodePromptRofi (line 1735) | func NextEpisodePromptRofi(userCurdConfig *CurdConfig) bool {
function StartNextEpisode (line 1760) | func StartNextEpisode(anime *Anime, userCurdConfig *CurdConfig, database...
function HandleLastEpisodeCompletion (line 1825) | func HandleLastEpisodeCompletion(userCurdConfig *CurdConfig, anime *Anim...
function handleSequelCheck (line 1875) | func handleSequelCheck(userCurdConfig *CurdConfig, anime *Anime, userTok...
function promptSequelNotInList (line 2058) | func promptSequelNotInList(sequel *SequelInfo, sequelTitle string, userT...
function ChangeProvider (line 2096) | func ChangeProvider(userCurdConfig *CurdConfig) {
FILE: internal/discord.go
function LoginClient (line 17) | func LoginClient(clientId string) error {
function DiscordPresence (line 32) | func DiscordPresence(anime Anime, IsPaused bool, currentPosition int, to...
function DiscordPresenceWithForce (line 36) | func DiscordPresenceWithForce(anime Anime, IsPaused bool, currentPositio...
function LogoutClient (line 137) | func LogoutClient() error {
function FormatTime (line 149) | func FormatTime(seconds int) string {
function ConvertSecondsToMinutes (line 160) | func ConvertSecondsToMinutes(seconds int) int {
FILE: internal/episode_list.go
type episodesResponse (line 13) | type episodesResponse struct
function getAllAnimeEpisodesList (line 35) | func getAllAnimeEpisodesList(showID, mode string) ([]string, error) {
function extractEpisodes (line 96) | func extractEpisodes(availableEpisodesDetail map[string]interface{}, mod...
FILE: internal/episode_url.go
type allanimeResponse (line 24) | type allanimeResponse struct
type result (line 37) | type result struct
type filemoonResponse (line 43) | type filemoonResponse struct
function decodeTobeparsed (line 49) | func decodeTobeparsed(blob string) string {
function decodeProviderID (line 107) | func decodeProviderID(encoded string) string {
function extractLinks (line 150) | func extractLinks(provider_id string) map[string]interface{} {
function normalizeAllanimeProviderPath (line 217) | func normalizeAllanimeProviderPath(providerID string) string {
function decodeBase64URLRaw (line 234) | func decodeBase64URLRaw(input string) ([]byte, error) {
function extractFilemoonLinks (line 241) | func extractFilemoonLinks(videoData map[string]interface{}) []string {
function getAllanimeEpisodeURL (line 389) | func getAllanimeEpisodeURL(config CurdConfig, id string, epNo int) ([]st...
function getEpisodeURLForMode (line 450) | func getEpisodeURLForMode(id, mode string, epNo int) ([]string, error) {
function getLinksFromSourceUrls (line 577) | func getLinksFromSourceUrls(sourceUrls []struct {
function getLinksFromURLs (line 611) | func getLinksFromURLs(validURLs []string) ([]string, error) {
function collectRemainingResults (line 734) | func collectRemainingResults(results chan result, orderedResults [][]str...
function flattenResults (line 753) | func flattenResults(results [][]string) []string {
FILE: internal/filler_list.go
type AnimeFillerListEpisode (line 10) | type AnimeFillerListEpisode struct
type EpisodesResponse (line 15) | type EpisodesResponse struct
function FetchFillerEpisodes (line 22) | func FetchFillerEpisodes(malID int) ([]int, error) {
function IsEpisodeFiller (line 71) | func IsEpisodeFiller(fillerEpisodes []int, episodeNumber int) bool {
function GetNextCanonEpisode (line 81) | func GetNextCanonEpisode(fillerEpisodes []int, currentEpisode int) int {
FILE: internal/globals.go
function SetGlobalAnime (line 9) | func SetGlobalAnime(anime *Anime) {
function GetGlobalAnime (line 14) | func GetGlobalAnime() *Anime {
function SetGlobalLogFile (line 19) | func SetGlobalLogFile(logFile string) {
function GetGlobalLogFile (line 24) | func GetGlobalLogFile() string {
FILE: internal/http_client.go
function SetCookiesForAnimepahe (line 12) | func SetCookiesForAnimepahe(u *url.URL, cookies []*http.Cookie) {
function init (line 18) | func init() {
FILE: internal/jikan.go
function GetEpisodeData (line 11) | func GetEpisodeData(animeID int, episodeNo int, anime *Anime) error {
function makeGetRequest (line 73) | func makeGetRequest(url string, headers map[string]string) (map[string]i...
function FetchJikanPictures (line 110) | func FetchJikanPictures(malID int) ([]string, error) {
type JikanAnimeData (line 145) | type JikanAnimeData struct
function FetchJikanAnimeData (line 158) | func FetchJikanAnimeData(malID int) (*JikanAnimeData, error) {
FILE: internal/links.go
function PrioritizeLink (line 16) | func PrioritizeLink(links []string) string {
FILE: internal/localTracking.go
function LocalAddAnime (line 15) | func LocalAddAnime(databaseFile string, anilistID int, allanimeID string...
function LocalDeleteAnime (line 42) | func LocalDeleteAnime(databaseFile string, anilistID int, allanimeID str...
function LocalGetAllAnime (line 84) | func LocalGetAllAnime(databaseFile string) []Anime {
function parseAnimeRow (line 130) | func parseAnimeRow(row []string) *Anime {
function GetAnimeName (line 177) | func GetAnimeName(anime Anime) string {
function LocalUpdateAnime (line 186) | func LocalUpdateAnime(databaseFile string, anilistID int, allanimeID str...
function LocalFindAnime (line 255) | func LocalFindAnime(animeList []Anime, anilistID int, allanimeID string)...
function WatchUntracked (line 270) | func WatchUntracked(userCurdConfig *CurdConfig) {
FILE: internal/player.go
constant defaultStreamReferrer (line 19) | defaultStreamReferrer = "allanime.day"
function getBundledMPVPath (line 24) | func getBundledMPVPath() (string, error) {
function resolveExecutable (line 34) | func resolveExecutable(binary string) (string, error) {
function candidatePlayerBinaries (line 55) | func candidatePlayerBinaries(configuredPlayer string) []string {
function resolveMPVBinary (line 88) | func resolveMPVBinary() (string, error) {
function resolveConfiguredPlayerBinary (line 101) | func resolveConfiguredPlayerBinary(configuredPlayer string) (string, str...
function isIINAPlayer (line 128) | func isIINAPlayer(effectivePlayerName string, resolvedPlayerBinary strin...
function translateMPVArgsForIINA (line 137) | func translateMPVArgsForIINA(mpvArgs []string) []string {
function isHTTPStreamLink (line 155) | func isHTTPStreamLink(link string) bool {
function hasMPVReferrerArg (line 160) | func hasMPVReferrerArg(args []string) bool {
function StartVideo (line 191) | func StartVideo(link string, args []string, title string, anime *Anime) ...
function joinArgs (line 374) | func joinArgs(args []string) string {
function MPVSendCommand (line 385) | func MPVSendCommand(ipcSocketPath string, command []interface{}) (interf...
function SeekMPV (line 452) | func SeekMPV(ipcSocketPath string, time int) (interface{}, error) {
function GetMPVPausedStatus (line 457) | func GetMPVPausedStatus(ipcSocketPath string) (bool, error) {
function GetMPVPlaybackSpeed (line 470) | func GetMPVPlaybackSpeed(ipcSocketPath string) (float64, error) {
function GetPercentageWatched (line 485) | func GetPercentageWatched(ipcSocketPath string) (float64, error) {
function PercentageWatched (line 507) | func PercentageWatched(playbackTime int, duration int) float64 {
function HasActivePlayback (line 515) | func HasActivePlayback(ipcSocketPath string) (bool, error) {
function IsMPVRunning (line 561) | func IsMPVRunning(socketPath string) bool {
function ExitMPV (line 596) | func ExitMPV(ipcSocketPath string) error {
type MPVEventListener (line 606) | type MPVEventListener struct
method ProcessMPVEvent (line 780) | func (detector *MPVEventListener) ProcessMPVEvent(propertyName string,...
method HasSeekOccurred (line 883) | func (detector *MPVEventListener) HasSeekOccurred() bool {
method HasPlayPauseChanged (line 898) | func (detector *MPVEventListener) HasPlayPauseChanged() bool {
function SetupMPVEventListening (line 617) | func SetupMPVEventListening(ipcSocketPath string) error {
function StartMPVEventListener (line 653) | func StartMPVEventListener(ipcSocketPath string, eventCallback func(stri...
function CreateMPVSeekDetector (line 765) | func CreateMPVSeekDetector(ipcSocketPath string) *MPVEventListener {
FILE: internal/provider.go
type Provider (line 4) | type Provider interface
function GetProvider (line 14) | func GetProvider() Provider {
function SearchAnime (line 28) | func SearchAnime(query, mode string) ([]SelectionOption, error) {
function EpisodesList (line 32) | func EpisodesList(showID, mode string) ([]string, error) {
function GetEpisodeURL (line 36) | func GetEpisodeURL(config CurdConfig, id string, epNo int) ([]string, er...
FILE: internal/provider_allanime.go
type AllanimeProvider (line 3) | type AllanimeProvider struct
method Name (line 5) | func (p *AllanimeProvider) Name() string {
method SearchAnime (line 9) | func (p *AllanimeProvider) SearchAnime(query, mode string) ([]Selectio...
method EpisodesList (line 13) | func (p *AllanimeProvider) EpisodesList(showID, mode string) ([]string...
method GetEpisodeURL (line 17) | func (p *AllanimeProvider) GetEpisodeURL(config CurdConfig, id string,...
FILE: internal/provider_animepahe.go
function getCookieFilePath (line 22) | func getCookieFilePath() string {
function saveCookies (line 26) | func saveCookies(cookies []*http.Cookie) {
function loadCookies (line 33) | func loadCookies() []*http.Cookie {
function checkCookiesValid (line 44) | func checkCookiesValid() bool {
type AnimepaheProvider (line 126) | type AnimepaheProvider struct
method ensureBypass (line 65) | func (p *AnimepaheProvider) ensureBypass() error {
method Name (line 128) | func (p *AnimepaheProvider) Name() string {
method SearchAnime (line 153) | func (p *AnimepaheProvider) SearchAnime(query, mode string) ([]Selecti...
method EpisodesList (line 211) | func (p *AnimepaheProvider) EpisodesList(showID, mode string) ([]strin...
method GetEpisodeURL (line 263) | func (p *AnimepaheProvider) GetEpisodeURL(config CurdConfig, id string...
method extractKwikM3u8 (line 430) | func (p *AnimepaheProvider) extractKwikM3u8(kwikUrl string) (string, e...
type AnimepaheSearchItem (line 132) | type AnimepaheSearchItem struct
type animepaheSearchResponse (line 145) | type animepaheSearchResponse struct
type animepaheEpisodesResponse (line 198) | type animepaheEpisodesResponse struct
function unpackKwik (line 471) | func unpackKwik(p string, a int, c int, k []string) string {
function contains (line 510) | func contains(slice []string, val string) bool {
FILE: internal/rofi.go
function GetTokenFromRofi (line 11) | func GetTokenFromRofi() (string, error) {
function GetUserInputFromRofi (line 38) | func GetUserInputFromRofi(message string) (string, error) {
FILE: internal/selection_menu.go
type Model (line 22) | type Model struct
method Init (line 82) | func (m Model) Init() tea.Cmd {
method Update (line 87) | func (m *Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
method replaceOptions (line 166) | func (m *Model) replaceOptions(options []SelectionOption) {
method View (line 209) | func (m Model) View() string {
method visibleItemsCount (line 243) | func (m Model) visibleItemsCount() int {
method filterOptions (line 249) | func (m *Model) filterOptions() {
type optionsRefreshedMsg (line 34) | type optionsRefreshedMsg struct
type SelectionRefreshConfig (line 38) | type SelectionRefreshConfig struct
type PreviewSelectionRefreshConfig (line 43) | type PreviewSelectionRefreshConfig struct
function detectHomeMenu (line 300) | func detectHomeMenu(options []SelectionOption) bool {
function findSelectionIndex (line 309) | func findSelectionIndex(options []SelectionOption, previousKey string, p...
function sortHomeMenuOptions (line 337) | func sortHomeMenuOptions(options []SelectionOption) []SelectionOption {
function previewOptionsToSortedSelection (line 362) | func previewOptionsToSortedSelection(options map[string]RofiSelectPrevie...
function DynamicSelectPreview (line 378) | func DynamicSelectPreview(options map[string]RofiSelectPreview, addnewop...
function DynamicSelectPreviewWithRefresh (line 382) | func DynamicSelectPreviewWithRefresh(options map[string]RofiSelectPrevie...
function preDownloadImages (line 468) | func preDownloadImages(options map[string]RofiSelectPreview, count int) {
function parsePreviewSelection (line 479) | func parsePreviewSelection(rawSelection string, selectionOptions []Selec...
function downloadToCache (line 503) | func downloadToCache(imageURL string) (string, error) {
function showCachedImagePreview (line 540) | func showCachedImagePreview(imageURL string) error {
function RofiSelect (line 556) | func RofiSelect(options []SelectionOption, isHomeMenu bool) (SelectionOp...
function RofiSelectWithRefresh (line 560) | func RofiSelectWithRefresh(options []SelectionOption, isHomeMenu bool, r...
function DynamicSelectFromSlice (line 618) | func DynamicSelectFromSlice(options []SelectionOption) (SelectionOption,...
function DynamicSelect (line 623) | func DynamicSelect(options []SelectionOption) (SelectionOption, error) {
function DynamicSelectWithRefresh (line 627) | func DynamicSelectWithRefresh(options []SelectionOption, refreshConfig *...
function dynamicSelectInternal (line 631) | func dynamicSelectInternal(options []SelectionOption, refreshConfig *Sel...
function buildRofiOptionsString (line 714) | func buildRofiOptionsString(options []SelectionOption, isHomeMenu bool) ...
function parseRofiSelection (line 728) | func parseRofiSelection(err error, rawSelection string, options []Select...
FILE: internal/structs.go
type AnimeTitle (line 3) | type AnimeTitle struct
type Anime (line 9) | type Anime struct
type FuzzyDate (line 26) | type FuzzyDate struct
type Skip (line 32) | type Skip struct
type SkipTimes (line 37) | type SkipTimes struct
type Episode (line 42) | type Episode struct
type NextEpisode (line 61) | type NextEpisode struct
type playingVideo (line 66) | type playingVideo struct
type User (line 73) | type User struct
type AniListAnime (line 82) | type AniListAnime struct
type Page (line 95) | type Page struct
type ResponseData (line 100) | type ResponseData struct
type Media (line 104) | type Media struct
type Entry (line 112) | type Entry struct
type AnimeList (line 123) | type AnimeList struct
type RofiSelectPreview (line 132) | type RofiSelectPreview struct
type SelectionOptionImage (line 137) | type SelectionOptionImage struct
type SelectionOption (line 144) | type SelectionOption struct
FILE: internal/unix_ipc.go
function connectToPipe (line 10) | func connectToPipe(ipcSocketPath string) (net.Conn, error) {
FILE: internal/windows_ipc.go
function connectToPipe (line 12) | func connectToPipe(ipcSocketPath string) (net.Conn, error) {
FILE: vendor/github.com/Microsoft/go-winio/backup.go
constant BackupData (line 23) | BackupData = uint32(iota + 1)
constant BackupEaData (line 24) | BackupEaData
constant BackupSecurity (line 25) | BackupSecurity
constant BackupAlternateData (line 26) | BackupAlternateData
constant BackupLink (line 27) | BackupLink
constant BackupPropertyData (line 28) | BackupPropertyData
constant BackupObjectId (line 29) | BackupObjectId
constant BackupReparseData (line 30) | BackupReparseData
constant BackupSparseBlock (line 31) | BackupSparseBlock
constant BackupTxfsData (line 32) | BackupTxfsData
constant StreamSparseAttributes (line 36) | StreamSparseAttributes = uint32(8)
constant WRITE_DAC (line 41) | WRITE_DAC = windows.WRITE_DAC
constant WRITE_OWNER (line 42) | WRITE_OWNER = windows.WRITE_OWNER
constant ACCESS_SYSTEM_SECURITY (line 43) | ACCESS_SYSTEM_SECURITY = windows.ACCESS_SYSTEM_SECURITY
type BackupHeader (line 47) | type BackupHeader struct
type win32StreamID (line 56) | type win32StreamID struct
type BackupStreamReader (line 65) | type BackupStreamReader struct
method Next (line 77) | func (r *BackupStreamReader) Next() (*BackupHeader, error) {
method Read (line 120) | func (r *BackupStreamReader) Read(b []byte) (int, error) {
function NewBackupStreamReader (line 71) | func NewBackupStreamReader(r io.Reader) *BackupStreamReader {
type BackupStreamWriter (line 138) | type BackupStreamWriter struct
method WriteHeader (line 149) | func (w *BackupStreamWriter) WriteHeader(hdr *BackupHeader) error {
method Write (line 182) | func (w *BackupStreamWriter) Write(b []byte) (int, error) {
function NewBackupStreamWriter (line 144) | func NewBackupStreamWriter(w io.Writer) *BackupStreamWriter {
type BackupFileReader (line 192) | type BackupFileReader struct
method Read (line 206) | func (r *BackupFileReader) Read(b []byte) (int, error) {
method Close (line 221) | func (r *BackupFileReader) Close() error {
function NewBackupFileReader (line 200) | func NewBackupFileReader(f *os.File, includeSecurity bool) *BackupFileRe...
type BackupFileWriter (line 231) | type BackupFileWriter struct
method Write (line 245) | func (w *BackupFileWriter) Write(b []byte) (int, error) {
method Close (line 260) | func (w *BackupFileWriter) Close() error {
function NewBackupFileWriter (line 239) | func NewBackupFileWriter(f *os.File, includeSecurity bool) *BackupFileWr...
function OpenForBackup (line 273) | func OpenForBackup(path string, access uint32, share uint32, createmode ...
FILE: vendor/github.com/Microsoft/go-winio/ea.go
type fileFullEaInformation (line 9) | type fileFullEaInformation struct
type ExtendedAttribute (line 25) | type ExtendedAttribute struct
function parseEa (line 31) | func parseEa(b []byte) (ea ExtendedAttribute, nb []byte, err error) {
function DecodeExtendedAttributes (line 60) | func DecodeExtendedAttributes(b []byte) (eas []ExtendedAttribute, err er...
function writeEa (line 73) | func writeEa(buf *bytes.Buffer, ea *ExtendedAttribute, last bool) error {
function EncodeExtendedAttributes (line 123) | func EncodeExtendedAttributes(eas []ExtendedAttribute) ([]byte, error) {
FILE: vendor/github.com/Microsoft/go-winio/file.go
type timeoutError (line 29) | type timeoutError struct
method Error (line 31) | func (*timeoutError) Error() string { return "i/o timeout" }
method Timeout (line 32) | func (*timeoutError) Timeout() bool { return true }
method Temporary (line 33) | func (*timeoutError) Temporary() bool { return true }
type timeoutChan (line 35) | type timeoutChan
type ioResult (line 41) | type ioResult struct
type ioOperation (line 47) | type ioOperation struct
function initIO (line 52) | func initIO() {
type win32File (line 63) | type win32File struct
method closeHandle (line 114) | func (f *win32File) closeHandle() {
method Close (line 131) | func (f *win32File) Close() error {
method IsClosed (line 137) | func (f *win32File) IsClosed() bool {
method prepareIO (line 143) | func (f *win32File) prepareIO() (*ioOperation, error) {
method asyncIO (line 174) | func (f *win32File) asyncIO(c *ioOperation, d *deadlineHandler, bytes ...
method Read (line 221) | func (f *win32File) Read(b []byte) (int, error) {
method Write (line 247) | func (f *win32File) Write(b []byte) (int, error) {
method SetReadDeadline (line 265) | func (f *win32File) SetReadDeadline(deadline time.Time) error {
method SetWriteDeadline (line 269) | func (f *win32File) SetWriteDeadline(deadline time.Time) error {
method Flush (line 273) | func (f *win32File) Flush() error {
method Fd (line 277) | func (f *win32File) Fd() uintptr {
type deadlineHandler (line 73) | type deadlineHandler struct
method set (line 281) | func (d *deadlineHandler) set(deadline time.Time) error {
function makeWin32File (line 82) | func makeWin32File(h windows.Handle) (*win32File, error) {
function MakeOpenFile (line 99) | func MakeOpenFile(h syscall.Handle) (io.ReadWriteCloser, error) {
function NewOpenFile (line 103) | func NewOpenFile(h windows.Handle) (io.ReadWriteCloser, error) {
function ioCompletionProcessor (line 157) | func ioCompletionProcessor(h windows.Handle) {
FILE: vendor/github.com/Microsoft/go-winio/fileinfo.go
type FileBasicInfo (line 15) | type FileBasicInfo struct
type alignedFileBasicInfo (line 24) | type alignedFileBasicInfo struct
function GetFileBasicInfo (line 31) | func GetFileBasicInfo(f *os.File) (*FileBasicInfo, error) {
function SetFileBasicInfo (line 48) | func SetFileBasicInfo(f *os.File, bi *FileBasicInfo) error {
type FileStandardInfo (line 67) | type FileStandardInfo struct
function GetFileStandardInfo (line 74) | func GetFileStandardInfo(f *os.File) (*FileStandardInfo, error) {
type FileIDInfo (line 88) | type FileIDInfo struct
function GetFileID (line 94) | func GetFileID(f *os.File) (*FileIDInfo, error) {
FILE: vendor/github.com/Microsoft/go-winio/hvsock.go
constant afHVSock (line 22) | afHVSock = 34
function HvsockGUIDWildcard (line 28) | func HvsockGUIDWildcard() guid.GUID { // 00000000-0000-0000-0000-0000000...
function HvsockGUIDBroadcast (line 33) | func HvsockGUIDBroadcast() guid.GUID { // ffffffff-ffff-ffff-ffff-ffffff...
function HvsockGUIDLoopback (line 43) | func HvsockGUIDLoopback() guid.GUID { // e0e16197-dd56-4a10-9195-5ee7a15...
function HvsockGUIDSiloHost (line 55) | func HvsockGUIDSiloHost() guid.GUID { // 36bd0c5c-7276-4223-88ba-7d03b65...
function HvsockGUIDChildren (line 65) | func HvsockGUIDChildren() guid.GUID { // 90db8b89-0d35-4f79-8ce9-49ea0ac...
function HvsockGUIDParent (line 80) | func HvsockGUIDParent() guid.GUID { // a42e7cda-d03f-480c-9cc2-a4de20abb878
function hvsockVsockServiceTemplate (line 90) | func hvsockVsockServiceTemplate() guid.GUID { // 00000000-facb-11e6-bd58...
type HvsockAddr (line 99) | type HvsockAddr struct
method Network (line 114) | func (*HvsockAddr) Network() string {
method String (line 118) | func (addr *HvsockAddr) String() string {
method raw (line 129) | func (addr *HvsockAddr) raw() rawHvsockAddr {
method fromRaw (line 137) | func (addr *HvsockAddr) fromRaw(raw *rawHvsockAddr) {
type rawHvsockAddr (line 104) | type rawHvsockAddr struct
method Sockaddr (line 146) | func (r *rawHvsockAddr) Sockaddr() (unsafe.Pointer, int32, error) {
method FromBytes (line 151) | func (r *rawHvsockAddr) FromBytes(b []byte) error {
function VsockServiceID (line 123) | func VsockServiceID(port uint32) guid.GUID {
type HvsockListener (line 167) | type HvsockListener struct
method opErr (line 223) | func (l *HvsockListener) opErr(op string, err error) error {
method Addr (line 228) | func (l *HvsockListener) Addr() net.Addr {
method Accept (line 233) | func (l *HvsockListener) Accept() (_ net.Conn, err error) {
method Close (line 284) | func (l *HvsockListener) Close() error {
type HvsockConn (line 175) | type HvsockConn struct
method opErr (line 443) | func (conn *HvsockConn) opErr(op string, err error) error {
method Read (line 451) | func (conn *HvsockConn) Read(b []byte) (int, error) {
method Write (line 473) | func (conn *HvsockConn) Write(b []byte) (int, error) {
method write (line 486) | func (conn *HvsockConn) write(b []byte) (int, error) {
method Close (line 507) | func (conn *HvsockConn) Close() error {
method IsClosed (line 511) | func (conn *HvsockConn) IsClosed() bool {
method shutdown (line 516) | func (conn *HvsockConn) shutdown(how int) error {
method CloseRead (line 534) | func (conn *HvsockConn) CloseRead() error {
method CloseWrite (line 544) | func (conn *HvsockConn) CloseWrite() error {
method LocalAddr (line 553) | func (conn *HvsockConn) LocalAddr() net.Addr {
method RemoteAddr (line 558) | func (conn *HvsockConn) RemoteAddr() net.Addr {
method SetDeadline (line 563) | func (conn *HvsockConn) SetDeadline(t time.Time) error {
method SetReadDeadline (line 575) | func (conn *HvsockConn) SetReadDeadline(t time.Time) error {
method SetWriteDeadline (line 580) | func (conn *HvsockConn) SetWriteDeadline(t time.Time) error {
function newHVSocket (line 182) | func newHVSocket() (*win32File, error) {
function ListenHvsock (line 197) | func ListenHvsock(addr *HvsockAddr) (_ *HvsockListener, err error) {
type HvsockDialer (line 289) | type HvsockDialer struct
method Dial (line 315) | func (d *HvsockDialer) Dial(ctx context.Context, addr *HvsockAddr) (co...
method redialWait (line 406) | func (d *HvsockDialer) redialWait(ctx context.Context) (err error) {
function Dial (line 306) | func Dial(ctx context.Context, addr *HvsockAddr) (conn *HvsockConn, err ...
function canRedial (line 432) | func canRedial(err error) bool {
FILE: vendor/github.com/Microsoft/go-winio/internal/fs/fs.go
constant NullHandle (line 16) | NullHandle windows.Handle = 0
constant FILE_ANY_ACCESS (line 50) | FILE_ANY_ACCESS AccessMask = 0
constant GENERIC_READ (line 52) | GENERIC_READ AccessMask = 0x8000_0000
constant GENERIC_WRITE (line 53) | GENERIC_WRITE AccessMask = 0x4000_0000
constant GENERIC_EXECUTE (line 54) | GENERIC_EXECUTE AccessMask = 0x2000_0000
constant GENERIC_ALL (line 55) | GENERIC_ALL AccessMask = 0x1000_0000
constant ACCESS_SYSTEM_SECURITY (line 56) | ACCESS_SYSTEM_SECURITY AccessMask = 0x0100_0000
constant FILE_READ_DATA (line 61) | FILE_READ_DATA AccessMask = (0x0001)
constant FILE_LIST_DIRECTORY (line 62) | FILE_LIST_DIRECTORY AccessMask = (0x0001)
constant FILE_WRITE_DATA (line 64) | FILE_WRITE_DATA AccessMask = (0x0002)
constant FILE_ADD_FILE (line 65) | FILE_ADD_FILE AccessMask = (0x0002)
constant FILE_APPEND_DATA (line 67) | FILE_APPEND_DATA AccessMask = (0x0004)
constant FILE_ADD_SUBDIRECTORY (line 68) | FILE_ADD_SUBDIRECTORY AccessMask = (0x0004)
constant FILE_CREATE_PIPE_INSTANCE (line 69) | FILE_CREATE_PIPE_INSTANCE AccessMask = (0x0004)
constant FILE_READ_EA (line 71) | FILE_READ_EA AccessMask = (0x0008)
constant FILE_READ_PROPERTIES (line 72) | FILE_READ_PROPERTIES AccessMask = FILE_READ_EA
constant FILE_WRITE_EA (line 74) | FILE_WRITE_EA AccessMask = (0x0010)
constant FILE_WRITE_PROPERTIES (line 75) | FILE_WRITE_PROPERTIES AccessMask = FILE_WRITE_EA
constant FILE_EXECUTE (line 77) | FILE_EXECUTE AccessMask = (0x0020)
constant FILE_TRAVERSE (line 78) | FILE_TRAVERSE AccessMask = (0x0020)
constant FILE_DELETE_CHILD (line 80) | FILE_DELETE_CHILD AccessMask = (0x0040)
constant FILE_READ_ATTRIBUTES (line 82) | FILE_READ_ATTRIBUTES AccessMask = (0x0080)
constant FILE_WRITE_ATTRIBUTES (line 84) | FILE_WRITE_ATTRIBUTES AccessMask = (0x0100)
constant FILE_ALL_ACCESS (line 86) | FILE_ALL_ACCESS AccessMask = (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZ...
constant FILE_GENERIC_READ (line 87) | FILE_GENERIC_READ AccessMask = (STANDARD_RIGHTS_READ | FILE_READ_DATA...
constant FILE_GENERIC_WRITE (line 88) | FILE_GENERIC_WRITE AccessMask = (STANDARD_RIGHTS_WRITE | FILE_WRITE_DA...
constant FILE_GENERIC_EXECUTE (line 89) | FILE_GENERIC_EXECUTE AccessMask = (STANDARD_RIGHTS_EXECUTE | FILE_READ_A...
constant SPECIFIC_RIGHTS_ALL (line 91) | SPECIFIC_RIGHTS_ALL AccessMask = 0x0000FFFF
constant DELETE (line 96) | DELETE AccessMask = 0x0001_0000
constant READ_CONTROL (line 97) | READ_CONTROL AccessMask = 0x0002_0000
constant WRITE_DAC (line 98) | WRITE_DAC AccessMask = 0x0004_0000
constant WRITE_OWNER (line 99) | WRITE_OWNER AccessMask = 0x0008_0000
constant SYNCHRONIZE (line 100) | SYNCHRONIZE AccessMask = 0x0010_0000
constant STANDARD_RIGHTS_REQUIRED (line 102) | STANDARD_RIGHTS_REQUIRED AccessMask = 0x000F_0000
constant STANDARD_RIGHTS_READ (line 104) | STANDARD_RIGHTS_READ AccessMask = READ_CONTROL
constant STANDARD_RIGHTS_WRITE (line 105) | STANDARD_RIGHTS_WRITE AccessMask = READ_CONTROL
constant STANDARD_RIGHTS_EXECUTE (line 106) | STANDARD_RIGHTS_EXECUTE AccessMask = READ_CONTROL
constant STANDARD_RIGHTS_ALL (line 108) | STANDARD_RIGHTS_ALL AccessMask = 0x001F_0000
type FileShareMode (line 111) | type FileShareMode
constant FILE_SHARE_NONE (line 115) | FILE_SHARE_NONE FileShareMode = 0x00
constant FILE_SHARE_READ (line 116) | FILE_SHARE_READ FileShareMode = 0x01
constant FILE_SHARE_WRITE (line 117) | FILE_SHARE_WRITE FileShareMode = 0x02
constant FILE_SHARE_DELETE (line 118) | FILE_SHARE_DELETE FileShareMode = 0x04
constant FILE_SHARE_VALID_FLAGS (line 119) | FILE_SHARE_VALID_FLAGS FileShareMode = 0x07
type FileCreationDisposition (line 122) | type FileCreationDisposition
constant CREATE_NEW (line 128) | CREATE_NEW FileCreationDisposition = 0x01
constant CREATE_ALWAYS (line 129) | CREATE_ALWAYS FileCreationDisposition = 0x02
constant OPEN_EXISTING (line 130) | OPEN_EXISTING FileCreationDisposition = 0x03
constant OPEN_ALWAYS (line 131) | OPEN_ALWAYS FileCreationDisposition = 0x04
constant TRUNCATE_EXISTING (line 132) | TRUNCATE_EXISTING FileCreationDisposition = 0x05
type NTFileCreationDisposition (line 136) | type NTFileCreationDisposition
constant FILE_SUPERSEDE (line 142) | FILE_SUPERSEDE NTFileCreationDisposition = 0x00
constant FILE_OPEN (line 143) | FILE_OPEN NTFileCreationDisposition = 0x01
constant FILE_CREATE (line 144) | FILE_CREATE NTFileCreationDisposition = 0x02
constant FILE_OPEN_IF (line 145) | FILE_OPEN_IF NTFileCreationDisposition = 0x03
constant FILE_OVERWRITE (line 146) | FILE_OVERWRITE NTFileCreationDisposition = 0x04
constant FILE_OVERWRITE_IF (line 147) | FILE_OVERWRITE_IF NTFileCreationDisposition = 0x05
constant FILE_MAXIMUM_DISPOSITION (line 148) | FILE_MAXIMUM_DISPOSITION NTFileCreationDisposition = 0x05
type FileFlagOrAttribute (line 155) | type FileFlagOrAttribute
constant FILE_FLAG_WRITE_THROUGH (line 161) | FILE_FLAG_WRITE_THROUGH FileFlagOrAttribute = 0x8000_0000
constant FILE_FLAG_OVERLAPPED (line 162) | FILE_FLAG_OVERLAPPED FileFlagOrAttribute = 0x4000_0000
constant FILE_FLAG_NO_BUFFERING (line 163) | FILE_FLAG_NO_BUFFERING FileFlagOrAttribute = 0x2000_0000
constant FILE_FLAG_RANDOM_ACCESS (line 164) | FILE_FLAG_RANDOM_ACCESS FileFlagOrAttribute = 0x1000_0000
constant FILE_FLAG_SEQUENTIAL_SCAN (line 165) | FILE_FLAG_SEQUENTIAL_SCAN FileFlagOrAttribute = 0x0800_0000
constant FILE_FLAG_DELETE_ON_CLOSE (line 166) | FILE_FLAG_DELETE_ON_CLOSE FileFlagOrAttribute = 0x0400_0000
constant FILE_FLAG_BACKUP_SEMANTICS (line 167) | FILE_FLAG_BACKUP_SEMANTICS FileFlagOrAttribute = 0x0200_0000
constant FILE_FLAG_POSIX_SEMANTICS (line 168) | FILE_FLAG_POSIX_SEMANTICS FileFlagOrAttribute = 0x0100_0000
constant FILE_FLAG_OPEN_REPARSE_POINT (line 169) | FILE_FLAG_OPEN_REPARSE_POINT FileFlagOrAttribute = 0x0020_0000
constant FILE_FLAG_OPEN_NO_RECALL (line 170) | FILE_FLAG_OPEN_NO_RECALL FileFlagOrAttribute = 0x0010_0000
constant FILE_FLAG_FIRST_PIPE_INSTANCE (line 171) | FILE_FLAG_FIRST_PIPE_INSTANCE FileFlagOrAttribute = 0x0008_0000
type NTCreateOptions (line 179) | type NTCreateOptions
constant FILE_DIRECTORY_FILE (line 185) | FILE_DIRECTORY_FILE NTCreateOptions = 0x0000_0001
constant FILE_WRITE_THROUGH (line 186) | FILE_WRITE_THROUGH NTCreateOptions = 0x0000_0002
constant FILE_SEQUENTIAL_ONLY (line 187) | FILE_SEQUENTIAL_ONLY NTCreateOptions = 0x0000_0004
constant FILE_NO_INTERMEDIATE_BUFFERING (line 188) | FILE_NO_INTERMEDIATE_BUFFERING NTCreateOptions = 0x0000_0008
constant FILE_SYNCHRONOUS_IO_ALERT (line 190) | FILE_SYNCHRONOUS_IO_ALERT NTCreateOptions = 0x0000_0010
constant FILE_SYNCHRONOUS_IO_NONALERT (line 191) | FILE_SYNCHRONOUS_IO_NONALERT NTCreateOptions = 0x0000_0020
constant FILE_NON_DIRECTORY_FILE (line 192) | FILE_NON_DIRECTORY_FILE NTCreateOptions = 0x0000_0040
constant FILE_CREATE_TREE_CONNECTION (line 193) | FILE_CREATE_TREE_CONNECTION NTCreateOptions = 0x0000_0080
constant FILE_COMPLETE_IF_OPLOCKED (line 195) | FILE_COMPLETE_IF_OPLOCKED NTCreateOptions = 0x0000_0100
constant FILE_NO_EA_KNOWLEDGE (line 196) | FILE_NO_EA_KNOWLEDGE NTCreateOptions = 0x0000_0200
constant FILE_DISABLE_TUNNELING (line 197) | FILE_DISABLE_TUNNELING NTCreateOptions = 0x0000_0400
constant FILE_RANDOM_ACCESS (line 198) | FILE_RANDOM_ACCESS NTCreateOptions = 0x0000_0800
constant FILE_DELETE_ON_CLOSE (line 200) | FILE_DELETE_ON_CLOSE NTCreateOptions = 0x0000_1000
constant FILE_OPEN_BY_FILE_ID (line 201) | FILE_OPEN_BY_FILE_ID NTCreateOptions = 0x0000_2000
constant FILE_OPEN_FOR_BACKUP_INTENT (line 202) | FILE_OPEN_FOR_BACKUP_INTENT NTCreateOptions = 0x0000_4000
constant FILE_NO_COMPRESSION (line 203) | FILE_NO_COMPRESSION NTCreateOptions = 0x0000_8000
constant SECURITY_ANONYMOUS (line 212) | SECURITY_ANONYMOUS FileSQSFlag = FileSQSFlag(SecurityAnonymous << 16)
constant SECURITY_IDENTIFICATION (line 213) | SECURITY_IDENTIFICATION FileSQSFlag = FileSQSFlag(SecurityIdentification...
constant SECURITY_IMPERSONATION (line 214) | SECURITY_IMPERSONATION FileSQSFlag = FileSQSFlag(SecurityImpersonation ...
constant SECURITY_DELEGATION (line 215) | SECURITY_DELEGATION FileSQSFlag = FileSQSFlag(SecurityDelegation << 16)
constant SECURITY_SQOS_PRESENT (line 217) | SECURITY_SQOS_PRESENT FileSQSFlag = 0x0010_0000
constant SECURITY_VALID_SQOS_FLAGS (line 218) | SECURITY_VALID_SQOS_FLAGS FileSQSFlag = 0x001F_0000
type GetFinalPathFlag (line 224) | type GetFinalPathFlag
constant GetFinalPathDefaultFlag (line 228) | GetFinalPathDefaultFlag GetFinalPathFlag = 0x0
constant FILE_NAME_NORMALIZED (line 230) | FILE_NAME_NORMALIZED GetFinalPathFlag = 0x0
constant FILE_NAME_OPENED (line 231) | FILE_NAME_OPENED GetFinalPathFlag = 0x8
constant VOLUME_NAME_DOS (line 233) | VOLUME_NAME_DOS GetFinalPathFlag = 0x0
constant VOLUME_NAME_GUID (line 234) | VOLUME_NAME_GUID GetFinalPathFlag = 0x1
constant VOLUME_NAME_NT (line 235) | VOLUME_NAME_NT GetFinalPathFlag = 0x2
constant VOLUME_NAME_NONE (line 236) | VOLUME_NAME_NONE GetFinalPathFlag = 0x4
function GetFinalPathNameByHandle (line 244) | func GetFinalPathNameByHandle(h windows.Handle, flags GetFinalPathFlag) ...
FILE: vendor/github.com/Microsoft/go-winio/internal/fs/security.go
type SecurityImpersonationLevel (line 4) | type SecurityImpersonationLevel
constant SecurityAnonymous (line 8) | SecurityAnonymous SecurityImpersonationLevel = 0
constant SecurityIdentification (line 9) | SecurityIdentification SecurityImpersonationLevel = 1
constant SecurityImpersonation (line 10) | SecurityImpersonation SecurityImpersonationLevel = 2
constant SecurityDelegation (line 11) | SecurityDelegation SecurityImpersonationLevel = 3
FILE: vendor/github.com/Microsoft/go-winio/internal/fs/zsyscall_windows.go
constant errnoERROR_IO_PENDING (line 19) | errnoERROR_IO_PENDING = 997
function errnoErr (line 29) | func errnoErr(e syscall.Errno) error {
function CreateFile (line 45) | func CreateFile(name string, access AccessMask, mode FileShareMode, sa *...
function _CreateFile (line 54) | func _CreateFile(name *uint16, access AccessMask, mode FileShareMode, sa...
FILE: vendor/github.com/Microsoft/go-winio/internal/socket/rawaddr.go
type RawSockaddr (line 13) | type RawSockaddr interface
FILE: vendor/github.com/Microsoft/go-winio/internal/socket/socket.go
constant socketError (line 23) | socketError = uintptr(^uint32(0))
function GetSockName (line 38) | func GetSockName(s windows.Handle, rsa RawSockaddr) error {
function GetPeerName (line 52) | func GetPeerName(s windows.Handle, rsa RawSockaddr) error {
function Bind (line 61) | func Bind(s windows.Handle, rsa RawSockaddr) (err error) {
type runtimeFunc (line 79) | type runtimeFunc struct
method Load (line 86) | func (f *runtimeFunc) Load() error {
function ConnectEx (line 122) | func ConnectEx(
function connectEx (line 150) | func connectEx(
FILE: vendor/github.com/Microsoft/go-winio/internal/socket/zsyscall_windows.go
constant errnoERROR_IO_PENDING (line 19) | errnoERROR_IO_PENDING = 997
function errnoErr (line 29) | func errnoErr(e syscall.Errno) error {
function bind (line 47) | func bind(s windows.Handle, name unsafe.Pointer, namelen int32) (err err...
function getpeername (line 55) | func getpeername(s windows.Handle, name unsafe.Pointer, namelen *int32) ...
function getsockname (line 63) | func getsockname(s windows.Handle, name unsafe.Pointer, namelen *int32) ...
FILE: vendor/github.com/Microsoft/go-winio/internal/stringbuffer/wstring.go
constant MinWStringCap (line 13) | MinWStringCap = 310
function newBuffer (line 25) | func newBuffer() []uint16 { return *(pathPool.Get().(*[]uint16)) }
function freeBuffer (line 29) | func freeBuffer(b []uint16) { pathPool.Put(&b) }
type WString (line 36) | type WString struct
method Free (line 54) | func (b *WString) Free() {
method ResizeTo (line 64) | func (b *WString) ResizeTo(c uint32) uint32 {
method Buffer (line 88) | func (b *WString) Buffer() []uint16 {
method Pointer (line 97) | func (b *WString) Pointer() *uint16 {
method String (line 107) | func (b *WString) String() string {
method Cap (line 124) | func (b *WString) Cap() uint32 {
method cap (line 131) | func (b *WString) cap() uint32 { return uint32(cap(b.b)) }
method empty (line 132) | func (b *WString) empty() bool { return b == nil || b.cap() == 0 }
function NewWString (line 48) | func NewWString() *WString {
FILE: vendor/github.com/Microsoft/go-winio/pipe.go
type PipeConn (line 32) | type PipeConn interface
type ioStatusBlock (line 46) | type ioStatusBlock struct
type objectAttributes (line 60) | type objectAttributes struct
type unicodeString (line 69) | type unicodeString struct
type securityDescriptor (line 86) | type securityDescriptor struct
type ntStatus (line 96) | type ntStatus
method Err (line 98) | func (status ntStatus) Err() error {
type win32Pipe (line 112) | type win32Pipe struct
method LocalAddr (line 127) | func (f *win32Pipe) LocalAddr() net.Addr {
method RemoteAddr (line 131) | func (f *win32Pipe) RemoteAddr() net.Addr {
method SetDeadline (line 135) | func (f *win32Pipe) SetDeadline(t time.Time) error {
method Disconnect (line 142) | func (f *win32Pipe) Disconnect() error {
type win32MessageBytePipe (line 119) | type win32MessageBytePipe struct
method CloseWrite (line 147) | func (f *win32MessageBytePipe) CloseWrite() error {
method Write (line 165) | func (f *win32MessageBytePipe) Write(b []byte) (int, error) {
method Read (line 177) | func (f *win32MessageBytePipe) Read(b []byte) (int, error) {
type pipeAddress (line 125) | type pipeAddress
method Network (line 198) | func (pipeAddress) Network() string {
method String (line 202) | func (s pipeAddress) String() string {
function tryDialPipe (line 207) | func tryDialPipe(ctx context.Context, path *string, access fs.AccessMask...
function DialPipe (line 237) | func DialPipe(path string, timeout *time.Duration) (net.Conn, error) {
function DialPipeContext (line 255) | func DialPipeContext(ctx context.Context, path string) (net.Conn, error) {
type PipeImpLevel (line 261) | type PipeImpLevel
constant PipeImpLevelAnonymous (line 264) | PipeImpLevelAnonymous = PipeImpLevel(fs.SECURITY_ANONYMOUS)
constant PipeImpLevelIdentification (line 265) | PipeImpLevelIdentification = PipeImpLevel(fs.SECURITY_IDENTIFICATION)
constant PipeImpLevelImpersonation (line 266) | PipeImpLevelImpersonation = PipeImpLevel(fs.SECURITY_IMPERSONATION)
constant PipeImpLevelDelegation (line 267) | PipeImpLevelDelegation = PipeImpLevel(fs.SECURITY_DELEGATION)
function DialPipeAccess (line 272) | func DialPipeAccess(ctx context.Context, path string, access uint32) (ne...
function DialPipeAccessImpLevel (line 279) | func DialPipeAccessImpLevel(ctx context.Context, path string, access uin...
type acceptResponse (line 309) | type acceptResponse struct
type win32PipeListener (line 314) | type win32PipeListener struct
method makeServerPipe (line 416) | func (l *win32PipeListener) makeServerPipe() (*win32File, error) {
method makeConnectedServerPipe (line 429) | func (l *win32PipeListener) makeConnectedServerPipe() (*win32File, err...
method listenerRoutine (line 459) | func (l *win32PipeListener) listenerRoutine() {
method Accept (line 555) | func (l *win32PipeListener) Accept() (net.Conn, error) {
method Close (line 575) | func (l *win32PipeListener) Close() error {
method Addr (line 584) | func (l *win32PipeListener) Addr() net.Addr {
function makeServerPipeHandle (line 323) | func makeServerPipeHandle(path string, sd []byte, c *PipeConfig, first b...
type PipeConfig (line 489) | type PipeConfig struct
function ListenPipe (line 510) | func ListenPipe(path string, c *PipeConfig) (net.Listener, error) {
function connectPipe (line 540) | func connectPipe(p *win32File) error {
FILE: vendor/github.com/Microsoft/go-winio/pkg/guid/guid.go
type Variant (line 21) | type Variant
constant VariantUnknown (line 27) | VariantUnknown Variant = iota
constant VariantNCS (line 28) | VariantNCS
constant VariantRFC4122 (line 29) | VariantRFC4122
constant VariantMicrosoft (line 30) | VariantMicrosoft
constant VariantFuture (line 31) | VariantFuture
type Version (line 37) | type Version
method String (line 39) | func (v Version) String() string {
function NewV4 (line 47) | func NewV4() (GUID, error) {
function NewV5 (line 67) | func NewV5(namespace GUID, name []byte) (GUID, error) {
function fromArray (line 83) | func fromArray(b [16]byte, order binary.ByteOrder) GUID {
method toArray (line 92) | func (g GUID) toArray(order binary.ByteOrder) [16]byte {
function FromArray (line 102) | func FromArray(b [16]byte) GUID {
method ToArray (line 108) | func (g GUID) ToArray() [16]byte {
function FromWindowsArray (line 113) | func FromWindowsArray(b [16]byte) GUID {
method ToWindowsArray (line 119) | func (g GUID) ToWindowsArray() [16]byte {
method String (line 123) | func (g GUID) String() string {
function FromString (line 136) | func FromString(s string) (GUID, error) {
method setVariant (line 175) | func (g *GUID) setVariant(v Variant) {
method Variant (line 195) | func (g GUID) Variant() Variant {
method setVersion (line 209) | func (g *GUID) setVersion(v Version) {
method Version (line 214) | func (g GUID) Version() Version {
method MarshalText (line 219) | func (g GUID) MarshalText() ([]byte, error) {
method UnmarshalText (line 225) | func (g *GUID) UnmarshalText(text []byte) error {
FILE: vendor/github.com/Microsoft/go-winio/pkg/guid/guid_nonwindows.go
type GUID (line 11) | type GUID struct
FILE: vendor/github.com/Microsoft/go-winio/pkg/guid/guid_windows.go
type GUID (line 13) | type GUID
FILE: vendor/github.com/Microsoft/go-winio/pkg/guid/variant_string.go
function _ (line 7) | func _() {
constant _Variant_name (line 18) | _Variant_name = "UnknownNCSRFC 4122MicrosoftFuture"
method String (line 22) | func (i Variant) String() string {
FILE: vendor/github.com/Microsoft/go-winio/privilege.go
constant SE_PRIVILEGE_ENABLED (line 28) | SE_PRIVILEGE_ENABLED = windows.SE_PRIVILEGE_ENABLED
constant ERROR_NOT_ALL_ASSIGNED (line 31) | ERROR_NOT_ALL_ASSIGNED windows.Errno = windows.ERROR_NOT_ALL_ASSIGNED
constant SeBackupPrivilege (line 33) | SeBackupPrivilege = "SeBackupPrivilege"
constant SeRestorePrivilege (line 34) | SeRestorePrivilege = "SeRestorePrivilege"
constant SeSecurityPrivilege (line 35) | SeSecurityPrivilege = "SeSecurityPrivilege"
type PrivilegeError (line 44) | type PrivilegeError struct
method Error (line 48) | func (e *PrivilegeError) Error() string {
function RunWithPrivilege (line 65) | func RunWithPrivilege(name string, fn func() error) error {
function RunWithPrivileges (line 70) | func RunWithPrivileges(names []string, fn func() error) error {
function mapPrivileges (line 89) | func mapPrivileges(names []string) ([]uint64, error) {
function EnableProcessPrivileges (line 108) | func EnableProcessPrivileges(names []string) error {
function DisableProcessPrivileges (line 113) | func DisableProcessPrivileges(names []string) error {
function enableDisableProcessPrivilege (line 117) | func enableDisableProcessPrivilege(names []string, action uint32) error {
function adjustPrivileges (line 134) | func adjustPrivileges(token windows.Token, privileges []uint64, action u...
function getPrivilegeName (line 153) | func getPrivilegeName(luid uint64) string {
function newThreadToken (line 172) | func newThreadToken() (windows.Token, error) {
function releaseThreadToken (line 190) | func releaseThreadToken(h windows.Token) {
FILE: vendor/github.com/Microsoft/go-winio/reparse.go
constant reparseTagMountPoint (line 16) | reparseTagMountPoint = 0xA0000003
constant reparseTagSymlink (line 17) | reparseTagSymlink = 0xA000000C
type reparseDataBuffer (line 20) | type reparseDataBuffer struct
type ReparsePoint (line 31) | type ReparsePoint struct
type UnsupportedReparsePointError (line 38) | type UnsupportedReparsePointError struct
method Error (line 42) | func (e *UnsupportedReparsePointError) Error() string {
function DecodeReparsePoint (line 48) | func DecodeReparsePoint(b []byte) (*ReparsePoint, error) {
function DecodeReparsePointData (line 53) | func DecodeReparsePointData(tag uint32, b []byte) (*ReparsePoint, error) {
function isDriveLetter (line 75) | func isDriveLetter(c byte) bool {
function EncodeReparsePoint (line 81) | func EncodeReparsePoint(rp *ReparsePoint) []byte {
FILE: vendor/github.com/Microsoft/go-winio/sd.go
type AccountLookupError (line 19) | type AccountLookupError struct
method Error (line 24) | func (e *AccountLookupError) Error() string {
method Unwrap (line 40) | func (e *AccountLookupError) Unwrap() error { return e.Err }
type SddlConversionError (line 42) | type SddlConversionError struct
method Error (line 47) | func (e *SddlConversionError) Error() string {
method Unwrap (line 51) | func (e *SddlConversionError) Unwrap() error { return e.Err }
function LookupSidByName (line 56) | func LookupSidByName(name string) (sid string, err error) {
function LookupNameBySid (line 85) | func LookupNameBySid(sid string) (name string, err error) {
function SddlToSecurityDescriptor (line 118) | func SddlToSecurityDescriptor(sddl string) ([]byte, error) {
function SecurityDescriptorToSddl (line 127) | func SecurityDescriptorToSddl(sd []byte) (string, error) {
FILE: vendor/github.com/Microsoft/go-winio/zsyscall_windows.go
constant errnoERROR_IO_PENDING (line 19) | errnoERROR_IO_PENDING = 997
function errnoErr (line 29) | func errnoErr(e syscall.Errno) error {
function adjustTokenPrivileges (line 75) | func adjustTokenPrivileges(token windows.Token, releaseAll bool, input *...
function convertSidToStringSid (line 88) | func convertSidToStringSid(sid *byte, str **uint16) (err error) {
function convertStringSidToSid (line 96) | func convertStringSidToSid(str *uint16, sid **byte) (err error) {
function impersonateSelf (line 104) | func impersonateSelf(level uint32) (err error) {
function lookupAccountName (line 112) | func lookupAccountName(systemName *uint16, accountName string, sid *byte...
function _lookupAccountName (line 121) | func _lookupAccountName(systemName *uint16, accountName *uint16, sid *by...
function lookupAccountSid (line 129) | func lookupAccountSid(systemName *uint16, sid *byte, name *uint16, nameS...
function lookupPrivilegeDisplayName (line 137) | func lookupPrivilegeDisplayName(systemName string, name *uint16, buffer ...
function _lookupPrivilegeDisplayName (line 146) | func _lookupPrivilegeDisplayName(systemName *uint16, name *uint16, buffe...
function lookupPrivilegeName (line 154) | func lookupPrivilegeName(systemName string, luid *uint64, buffer *uint16...
function _lookupPrivilegeName (line 163) | func _lookupPrivilegeName(systemName *uint16, luid *uint64, buffer *uint...
function lookupPrivilegeValue (line 171) | func lookupPrivilegeValue(systemName string, name string, luid *uint64) ...
function _lookupPrivilegeValue (line 185) | func _lookupPrivilegeValue(systemName *uint16, name *uint16, luid *uint6...
function openThreadToken (line 193) | func openThreadToken(thread windows.Handle, accessMask uint32, openAsSel...
function revertToSelf (line 205) | func revertToSelf() (err error) {
function backupRead (line 213) | func backupRead(h windows.Handle, b []byte, bytesRead *uint32, abort boo...
function backupWrite (line 233) | func backupWrite(h windows.Handle, b []byte, bytesWritten *uint32, abort...
function cancelIoEx (line 253) | func cancelIoEx(file windows.Handle, o *windows.Overlapped) (err error) {
function connectNamedPipe (line 261) | func connectNamedPipe(pipe windows.Handle, o *windows.Overlapped) (err e...
function createIoCompletionPort (line 269) | func createIoCompletionPort(file windows.Handle, port windows.Handle, ke...
function createNamedPipe (line 278) | func createNamedPipe(name string, flags uint32, pipeMode uint32, maxInst...
function _createNamedPipe (line 287) | func _createNamedPipe(name *uint16, flags uint32, pipeMode uint32, maxIn...
function disconnectNamedPipe (line 296) | func disconnectNamedPipe(pipe windows.Handle) (err error) {
function getCurrentThread (line 304) | func getCurrentThread() (h windows.Handle) {
function getNamedPipeHandleState (line 310) | func getNamedPipeHandleState(pipe windows.Handle, state *uint32, curInst...
function getNamedPipeInfo (line 318) | func getNamedPipeInfo(pipe windows.Handle, flags *uint32, outSize *uint3...
function getQueuedCompletionStatus (line 326) | func getQueuedCompletionStatus(port windows.Handle, bytes *uint32, key *...
function setFileCompletionNotificationModes (line 334) | func setFileCompletionNotificationModes(h windows.Handle, flags uint8) (...
function ntCreateNamedPipeFile (line 342) | func ntCreateNamedPipeFile(pipe *windows.Handle, access ntAccessMask, oa...
function rtlDefaultNpAcl (line 348) | func rtlDefaultNpAcl(dacl *uintptr) (status ntStatus) {
function rtlDosPathNameToNtPathName (line 354) | func rtlDosPathNameToNtPathName(name *uint16, ntName *unicodeString, fil...
function rtlNtStatusToDosError (line 360) | func rtlNtStatusToDosError(status ntStatus) (winerr error) {
function wsaGetOverlappedResult (line 368) | func wsaGetOverlappedResult(h windows.Handle, o *windows.Overlapped, byt...
FILE: vendor/github.com/aymanbagabas/go-osc52/v2/osc52.go
type Clipboard (line 64) | type Clipboard
constant SystemClipboard (line 68) | SystemClipboard Clipboard = 'c'
constant PrimaryClipboard (line 70) | PrimaryClipboard = 'p'
type Mode (line 74) | type Mode
constant DefaultMode (line 78) | DefaultMode Mode = iota
constant ScreenMode (line 80) | ScreenMode
constant TmuxMode (line 83) | TmuxMode
type Operation (line 87) | type Operation
constant SetOperation (line 91) | SetOperation Operation = iota
constant QueryOperation (line 93) | QueryOperation
constant ClearOperation (line 95) | ClearOperation
type Sequence (line 99) | type Sequence struct
method String (line 112) | func (s Sequence) String() string {
method WriteTo (line 163) | func (s Sequence) WriteTo(out io.Writer) (int64, error) {
method Mode (line 169) | func (s Sequence) Mode(m Mode) Sequence {
method Tmux (line 181) | func (s Sequence) Tmux() Sequence {
method Screen (line 189) | func (s Sequence) Screen() Sequence {
method Clipboard (line 194) | func (s Sequence) Clipboard(c Clipboard) Sequence {
method Primary (line 203) | func (s Sequence) Primary() Sequence {
method Limit (line 213) | func (s Sequence) Limit(l int) Sequence {
method Operation (line 224) | func (s Sequence) Operation(o Operation) Sequence {
method Clear (line 233) | func (s Sequence) Clear() Sequence {
method Query (line 241) | func (s Sequence) Query() Sequence {
method SetString (line 247) | func (s Sequence) SetString(strs ...string) Sequence {
method seqStart (line 281) | func (s Sequence) seqStart() string {
method seqEnd (line 294) | func (s Sequence) seqEnd() string {
function New (line 254) | func New(strs ...string) Sequence {
function Query (line 269) | func Query() Sequence {
function Clear (line 277) | func Clear() Sequence {
FILE: vendor/github.com/charmbracelet/bubbletea/commands.go
function Batch (line 15) | func Batch(cmds ...Cmd) Cmd {
type BatchMsg (line 37) | type BatchMsg
function Sequence (line 41) | func Sequence(cmds ...Cmd) Cmd {
type sequenceMsg (line 48) | type sequenceMsg
function Every (line 96) | func Every(duration time.Duration, fn func(time.Time) Msg) Cmd {
function Tick (line 148) | func Tick(d time.Duration, fn func(time.Time) Msg) Cmd {
function Sequentially (line 174) | func Sequentially(cmds ...Cmd) Cmd {
type setWindowTitleMsg (line 189) | type setWindowTitleMsg
function SetWindowTitle (line 199) | func SetWindowTitle(title string) Cmd {
type windowSizeMsg (line 205) | type windowSizeMsg struct
function WindowSize (line 212) | func WindowSize() Cmd {
FILE: vendor/github.com/charmbracelet/bubbletea/exec.go
type execMsg (line 10) | type execMsg struct
function Exec (line 22) | func Exec(c ExecCommand, fn ExecCallback) Cmd {
function ExecProcess (line 50) | func ExecProcess(c *exec.Cmd, fn ExecCallback) Cmd {
type ExecCallback (line 56) | type ExecCallback
type ExecCommand (line 60) | type ExecCommand interface
function wrapExecCommand (line 69) | func wrapExecCommand(c *exec.Cmd) ExecCommand {
type osExecCommand (line 75) | type osExecCommand struct
method SetStdin (line 78) | func (c *osExecCommand) SetStdin(r io.Reader) {
method SetStdout (line 86) | func (c *osExecCommand) SetStdout(w io.Writer) {
method SetStderr (line 94) | func (c *osExecCommand) SetStderr(w io.Writer) {
method exec (line 102) | func (p *Program) exec(c ExecCommand, fn ExecCallback) {
FILE: vendor/github.com/charmbracelet/bubbletea/focus.go
type FocusMsg (line 5) | type FocusMsg struct
type BlurMsg (line 9) | type BlurMsg struct
FILE: vendor/github.com/charmbracelet/bubbletea/inputreader_other.go
function newInputReader (line 12) | func newInputReader(r io.Reader) (cancelreader.CancelReader, error) {
FILE: vendor/github.com/charmbracelet/bubbletea/inputreader_windows.go
type conInputReader (line 18) | type conInputReader struct
method Cancel (line 57) | func (r *conInputReader) Cancel() bool {
method Close (line 64) | func (r *conInputReader) Close() error {
method Read (line 76) | func (r *conInputReader) Read(_ []byte) (n int, err error) {
function newInputReader (line 28) | func newInputReader(r io.Reader) (cancelreader.CancelReader, error) {
function prepareConsole (line 83) | func prepareConsole(input windows.Handle, modes ...uint32) (originalMode...
type cancelMixin (line 100) | type cancelMixin struct
method setCanceled (line 105) | func (c *cancelMixin) setCanceled() {
method isCanceled (line 112) | func (c *cancelMixin) isCanceled() bool {
FILE: vendor/github.com/charmbracelet/bubbletea/key.go
type KeyMsg (line 45) | type KeyMsg
method String (line 49) | func (k KeyMsg) String() (str string) {
type Key (line 54) | type Key struct
method String (line 67) | func (k Key) String() (str string) {
type KeyType (line 108) | type KeyType
method String (line 110) | func (k KeyType) String() (str string) {
constant keyNUL (line 123) | keyNUL KeyType = 0
constant keySOH (line 124) | keySOH KeyType = 1
constant keySTX (line 125) | keySTX KeyType = 2
constant keyETX (line 126) | keyETX KeyType = 3
constant keyEOT (line 127) | keyEOT KeyType = 4
constant keyENQ (line 128) | keyENQ KeyType = 5
constant keyACK (line 129) | keyACK KeyType = 6
constant keyBEL (line 130) | keyBEL KeyType = 7
constant keyBS (line 131) | keyBS KeyType = 8
constant keyHT (line 132) | keyHT KeyType = 9
constant keyLF (line 133) | keyLF KeyType = 10
constant keyVT (line 134) | keyVT KeyType = 11
constant keyFF (line 135) | keyFF KeyType = 12
constant keyCR (line 136) | keyCR KeyType = 13
constant keySO (line 137) | keySO KeyType = 14
constant keySI (line 138) | keySI KeyType = 15
constant keyDLE (line 139) | keyDLE KeyType = 16
constant keyDC1 (line 140) | keyDC1 KeyType = 17
constant keyDC2 (line 141) | keyDC2 KeyType = 18
constant keyDC3 (line 142) | keyDC3 KeyType = 19
constant keyDC4 (line 143) | keyDC4 KeyType = 20
constant keyNAK (line 144) | keyNAK KeyType = 21
constant keySYN (line 145) | keySYN KeyType = 22
constant keyETB (line 146) | keyETB KeyType = 23
constant keyCAN (line 147) | keyCAN KeyType = 24
constant keyEM (line 148) | keyEM KeyType = 25
constant keySUB (line 149) | keySUB KeyType = 26
constant keyESC (line 150) | keyESC KeyType = 27
constant keyFS (line 151) | keyFS KeyType = 28
constant keyGS (line 152) | keyGS KeyType = 29
constant keyRS (line 153) | keyRS KeyType = 30
constant keyUS (line 154) | keyUS KeyType = 31
constant keyDEL (line 155) | keyDEL KeyType = 127
constant KeyNull (line 160) | KeyNull KeyType = keyNUL
constant KeyBreak (line 161) | KeyBreak KeyType = keyETX
constant KeyEnter (line 162) | KeyEnter KeyType = keyCR
constant KeyBackspace (line 163) | KeyBackspace KeyType = keyDEL
constant KeyTab (line 164) | KeyTab KeyType = keyHT
constant KeyEsc (line 165) | KeyEsc KeyType = keyESC
constant KeyEscape (line 166) | KeyEscape KeyType = keyESC
constant KeyCtrlAt (line 168) | KeyCtrlAt KeyType = keyNUL
constant KeyCtrlA (line 169) | KeyCtrlA KeyType = keySOH
constant KeyCtrlB (line 170) | KeyCtrlB KeyType = keySTX
constant KeyCtrlC (line 171) | KeyCtrlC KeyType = keyETX
constant KeyCtrlD (line 172) | KeyCtrlD KeyType = keyEOT
constant KeyCtrlE (line 173) | KeyCtrlE KeyType = keyENQ
constant KeyCtrlF (line 174) | KeyCtrlF KeyType = keyACK
constant KeyCtrlG (line 175) | KeyCtrlG KeyType = keyBEL
constant KeyCtrlH (line 176) | KeyCtrlH KeyType = keyBS
constant KeyCtrlI (line 177) | KeyCtrlI KeyType = keyHT
constant KeyCtrlJ (line 178) | KeyCtrlJ KeyType = keyLF
constant KeyCtrlK (line 179) | KeyCtrlK KeyType = keyVT
constant KeyCtrlL (line 180) | KeyCtrlL KeyType = keyFF
constant KeyCtrlM (line 181) | KeyCtrlM KeyType = keyCR
constant KeyCtrlN (line 182) | KeyCtrlN KeyType = keySO
constant KeyCtrlO (line 183) | KeyCtrlO KeyType = keySI
constant KeyCtrlP (line 184) | KeyCtrlP KeyType = keyDLE
constant KeyCtrlQ (line 185) | KeyCtrlQ KeyType = keyDC1
constant KeyCtrlR (line 186) | KeyCtrlR KeyType = keyDC2
constant KeyCtrlS (line 187) | KeyCtrlS KeyType = keyDC3
constant KeyCtrlT (line 188) | KeyCtrlT KeyType = keyDC4
constant KeyCtrlU (line 189) | KeyCtrlU KeyType = keyNAK
constant KeyCtrlV (line 190) | KeyCtrlV KeyType = keySYN
constant KeyCtrlW (line 191) | KeyCtrlW KeyType = keyETB
constant KeyCtrlX (line 192) | KeyCtrlX KeyType = keyCAN
constant KeyCtrlY (line 193) | KeyCtrlY KeyType = keyEM
constant KeyCtrlZ (line 194) | KeyCtrlZ KeyType = keySUB
constant KeyCtrlOpenBracket (line 195) | KeyCtrlOpenBracket KeyType = keyESC
constant KeyCtrlBackslash (line 196) | KeyCtrlBackslash KeyType = keyFS
constant KeyCtrlCloseBracket (line 197) | KeyCtrlCloseBracket KeyType = keyGS
constant KeyCtrlCaret (line 198) | KeyCtrlCaret KeyType = keyRS
constant KeyCtrlUnderscore (line 199) | KeyCtrlUnderscore KeyType = keyUS
constant KeyCtrlQuestionMark (line 200) | KeyCtrlQuestionMark KeyType = keyDEL
constant KeyRunes (line 205) | KeyRunes KeyType = -(iota + 1)
constant KeyUp (line 206) | KeyUp
constant KeyDown (line 207) | KeyDown
constant KeyRight (line 208) | KeyRight
constant KeyLeft (line 209) | KeyLeft
constant KeyShiftTab (line 210) | KeyShiftTab
constant KeyHome (line 211) | KeyHome
constant KeyEnd (line 212) | KeyEnd
constant KeyPgUp (line 213) | KeyPgUp
constant KeyPgDown (line 214) | KeyPgDown
constant KeyCtrlPgUp (line 215) | KeyCtrlPgUp
constant KeyCtrlPgDown (line 216) | KeyCtrlPgDown
constant KeyDelete (line 217) | KeyDelete
constant KeyInsert (line 218) | KeyInsert
constant KeySpace (line 219) | KeySpace
constant KeyCtrlUp (line 220) | KeyCtrlUp
constant KeyCtrlDown (line 221) | KeyCtrlDown
constant KeyCtrlRight (line 222) | KeyCtrlRight
constant KeyCtrlLeft (line 223) | KeyCtrlLeft
constant KeyCtrlHome (line 224) | KeyCtrlHome
constant KeyCtrlEnd (line 225) | KeyCtrlEnd
constant KeyShiftUp (line 226) | KeyShiftUp
constant KeyShiftDown (line 227) | KeyShiftDown
constant KeyShiftRight (line 228) | KeyShiftRight
constant KeyShiftLeft (line 229) | KeyShiftLeft
constant KeyShiftHome (line 230) | KeyShiftHome
constant KeyShiftEnd (line 231) | KeyShiftEnd
constant KeyCtrlShiftUp (line 232) | KeyCtrlShiftUp
constant KeyCtrlShiftDown (line 233) | KeyCtrlShiftDown
constant KeyCtrlShiftLeft (line 234) | KeyCtrlShiftLeft
constant KeyCtrlShiftRight (line 235) | KeyCtrlShiftRight
constant KeyCtrlShiftHome (line 236) | KeyCtrlShiftHome
constant KeyCtrlShiftEnd (line 237) | KeyCtrlShiftEnd
constant KeyF1 (line 238) | KeyF1
constant KeyF2 (line 239) | KeyF2
constant KeyF3 (line 240) | KeyF3
constant KeyF4 (line 241) | KeyF4
constant KeyF5 (line 242) | KeyF5
constant KeyF6 (line 243) | KeyF6
constant KeyF7 (line 244) | KeyF7
constant KeyF8 (line 245) | KeyF8
constant KeyF9 (line 246) | KeyF9
constant KeyF10 (line 247) | KeyF10
constant KeyF11 (line 248) | KeyF11
constant KeyF12 (line 249) | KeyF12
constant KeyF13 (line 250) | KeyF13
constant KeyF14 (line 251) | KeyF14
constant KeyF15 (line 252) | KeyF15
constant KeyF16 (line 253) | KeyF16
constant KeyF17 (line 254) | KeyF17
constant KeyF18 (line 255) | KeyF18
constant KeyF19 (line 256) | KeyF19
constant KeyF20 (line 257) | KeyF20
type unknownInputByteMsg (line 538) | type unknownInputByteMsg
method String (line 540) | func (u unknownInputByteMsg) String() string {
type unknownCSISequenceMsg (line 548) | type unknownCSISequenceMsg
method String (line 550) | func (u unknownCSISequenceMsg) String() string {
function readAnsiInputs (line 558) | func readAnsiInputs(ctx context.Context, msgs chan<- Msg, input io.Reade...
function detectOneMsg (line 614) | func detectOneMsg(b []byte, canHaveMoreData bool) (w int, msg Msg) {
FILE: vendor/github.com/charmbracelet/bubbletea/key_other.go
function readInputs (line 11) | func readInputs(ctx context.Context, msgs chan<- Msg, input io.Reader) e...
FILE: vendor/github.com/charmbracelet/bubbletea/key_sequences.go
function detectSequence (line 57) | func detectSequence(input []byte) (hasSeq bool, width int, msg Msg) {
function detectBracketedPaste (line 83) | func detectBracketedPaste(input []byte) (hasBp bool, width int, msg Msg) {
function detectReportFocus (line 123) | func detectReportFocus(input []byte) (hasRF bool, width int, msg Msg) {
FILE: vendor/github.com/charmbracelet/bubbletea/key_windows.go
function readInputs (line 16) | func readInputs(ctx context.Context, msgs chan<- Msg, input io.Reader) e...
function readConInputs (line 24) | func readConInputs(ctx context.Context, msgsch chan<- Msg, con *conInput...
function mouseEventButton (line 97) | func mouseEventButton(p, s coninput.ButtonState) (button MouseButton, ac...
function mouseEvent (line 136) | func mouseEvent(p coninput.ButtonState, e coninput.MouseEventRecord) Mou...
function keyType (line 187) | func keyType(e coninput.KeyEventRecord) KeyType {
FILE: vendor/github.com/charmbracelet/bubbletea/logging.go
function LogToFile (line 23) | func LogToFile(path string, prefix string) (*os.File, error) {
type LogOptionsSetter (line 29) | type LogOptionsSetter interface
function LogToFileWith (line 35) | func LogToFileWith(path string, prefix string, log LogOptionsSetter) (*o...
FILE: vendor/github.com/charmbracelet/bubbletea/mouse.go
type MouseMsg (line 8) | type MouseMsg
method String (line 11) | func (m MouseMsg) String() string {
type MouseEvent (line 17) | type MouseEvent struct
method IsWheel (line 31) | func (m MouseEvent) IsWheel() bool {
method String (line 37) | func (m MouseEvent) String() (s string) {
type MouseAction (line 71) | type MouseAction
constant MouseActionPress (line 75) | MouseActionPress MouseAction = iota
constant MouseActionRelease (line 76) | MouseActionRelease
constant MouseActionMotion (line 77) | MouseActionMotion
type MouseButton (line 87) | type MouseButton
constant MouseButtonNone (line 107) | MouseButtonNone MouseButton = iota
constant MouseButtonLeft (line 108) | MouseButtonLeft
constant MouseButtonMiddle (line 109) | MouseButtonMiddle
constant MouseButtonRight (line 110) | MouseButtonRight
constant MouseButtonWheelUp (line 111) | MouseButtonWheelUp
constant MouseButtonWheelDown (line 112) | MouseButtonWheelDown
constant MouseButtonWheelLeft (line 113) | MouseButtonWheelLeft
constant MouseButtonWheelRight (line 114) | MouseButtonWheelRight
constant MouseButtonBackward (line 115) | MouseButtonBackward
constant MouseButtonForward (line 116) | MouseButtonForward
constant MouseButton10 (line 117) | MouseButton10
constant MouseButton11 (line 118) | MouseButton11
type MouseEventType (line 139) | type MouseEventType
constant MouseUnknown (line 145) | MouseUnknown MouseEventType = iota
constant MouseLeft (line 146) | MouseLeft
constant MouseRight (line 147) | MouseRight
constant MouseMiddle (line 148) | MouseMiddle
constant MouseRelease (line 149) | MouseRelease
constant MouseWheelUp (line 150) | MouseWheelUp
constant MouseWheelDown (line 151) | MouseWheelDown
constant MouseWheelLeft (line 152) | MouseWheelLeft
constant MouseWheelRight (line 153) | MouseWheelRight
constant MouseBackward (line 154) | MouseBackward
constant MouseForward (line 155) | MouseForward
constant MouseMotion (line 156) | MouseMotion
function parseSGRMouseEvent (line 172) | func parseSGRMouseEvent(buf []byte) MouseEvent {
constant x10MouseByteOffset (line 203) | x10MouseByteOffset = 32
function parseX10MouseEvent (line 214) | func parseX10MouseEvent(buf []byte) MouseEvent {
function parseMouseButton (line 226) | func parseMouseButton(b int, isSGR bool) MouseEvent {
FILE: vendor/github.com/charmbracelet/bubbletea/nil_renderer.go
type nilRenderer (line 3) | type nilRenderer struct
method start (line 5) | func (n nilRenderer) start() {}
method stop (line 6) | func (n nilRenderer) stop() {}
method kill (line 7) | func (n nilRenderer) kill() {}
method write (line 8) | func (n nilRenderer) write(_ string) {}
method repaint (line 9) | func (n nilRenderer) repaint() {}
method clearScreen (line 10) | func (n nilRenderer) clearScreen() {}
method altScreen (line 11) | func (n nilRenderer) altScreen() bool { return false }
method enterAltScreen (line 12) | func (n nilRenderer) enterAltScreen() {}
method exitAltScreen (line 13) | func (n nilRenderer) exitAltScreen() {}
method showCursor (line 14) | func (n nilRenderer) showCursor() {}
method hideCursor (line 15) | func (n nilRenderer) hideCursor() {}
method enableMouseCellMotion (line 16) | func (n nilRenderer) enableMouseCellMotion() {}
method disableMouseCellMotion (line 17) | func (n nilRenderer) disableMouseCellMotion() {}
method enableMouseAllMotion (line 18) | func (n nilRenderer) enableMouseAllMotion() {}
method disableMouseAllMotion (line 19) | func (n nilRenderer) disableMouseAllMotion() {}
method enableBracketedPaste (line 20) | func (n nilRenderer) enableBracketedPaste() {}
method disableBracketedPaste (line 21) | func (n nilRenderer) disableBracketedPaste() {}
method enableMouseSGRMode (line 22) | func (n nilRenderer) enableMouseSGRMode() {}
method disableMouseSGRMode (line 23) | func (n nilRenderer) disableMouseSGRMode() {}
method bracketedPasteActive (line 24) | func (n nilRenderer) bracketedPasteActive() bool { return false }
method setWindowTitle (line 25) | func (n nilRenderer) setWindowTitle(_ string) {}
method reportFocus (line 26) | func (n nilRenderer) reportFocus() bool { return false }
method enableReportFocus (line 27) | func (n nilRenderer) enableReportFocus() {}
method disableReportFocus (line 28) | func (n nilRenderer) disableReportFocus() {}
FILE: vendor/github.com/charmbracelet/bubbletea/options.go
type ProgramOption (line 15) | type ProgramOption
function WithContext (line 20) | func WithContext(ctx context.Context) ProgramOption {
function WithOutput (line 28) | func WithOutput(output io.Writer) ProgramOption {
function WithInput (line 38) | func WithInput(input io.Reader) ProgramOption {
function WithInputTTY (line 46) | func WithInputTTY() ProgramOption {
function WithEnvironment (line 63) | func WithEnvironment(env []string) ProgramOption {
function WithoutSignalHandler (line 71) | func WithoutSignalHandler() ProgramOption {
function WithoutCatchPanics (line 81) | func WithoutCatchPanics() ProgramOption {
function WithoutSignals (line 89) | func WithoutSignals() ProgramOption {
function WithAltScreen (line 109) | func WithAltScreen() ProgramOption {
function WithoutBracketedPaste (line 116) | func WithoutBracketedPaste() ProgramOption {
function WithMouseCellMotion (line 137) | func WithMouseCellMotion() ProgramOption {
function WithMouseAllMotion (line 162) | func WithMouseAllMotion() ProgramOption {
function WithoutRenderer (line 177) | func WithoutRenderer() ProgramOption {
function WithANSICompressor (line 191) | func WithANSICompressor() ProgramOption {
function WithFilter (line 226) | func WithFilter(filter func(Model, Msg) Msg) ProgramOption {
function WithFPS (line 235) | func WithFPS(fps int) ProgramOption {
function WithReportFocus (line 248) | func WithReportFocus() ProgramOption {
FILE: vendor/github.com/charmbracelet/bubbletea/renderer.go
type renderer (line 4) | type renderer interface
type repaintMsg (line 85) | type repaintMsg struct
FILE: vendor/github.com/charmbracelet/bubbletea/screen.go
type WindowSizeMsg (line 7) | type WindowSizeMsg struct
function ClearScreen (line 18) | func ClearScreen() Msg {
type clearScreenMsg (line 24) | type clearScreenMsg struct
function EnterAltScreen (line 32) | func EnterAltScreen() Msg {
type enterAltScreenMsg (line 39) | type enterAltScreenMsg struct
function ExitAltScreen (line 47) | func ExitAltScreen() Msg {
type exitAltScreenMsg (line 53) | type exitAltScreenMsg struct
function EnableMouseCellMotion (line 61) | func EnableMouseCellMotion() Msg {
type enableMouseCellMotionMsg (line 68) | type enableMouseCellMotionMsg struct
function EnableMouseAllMotion (line 79) | func EnableMouseAllMotion() Msg {
type enableMouseAllMotionMsg (line 86) | type enableMouseAllMotionMsg struct
function DisableMouse (line 89) | func DisableMouse() Msg {
type disableMouseMsg (line 95) | type disableMouseMsg struct
function HideCursor (line 101) | func HideCursor() Msg {
type hideCursorMsg (line 107) | type hideCursorMsg struct
function ShowCursor (line 111) | func ShowCursor() Msg {
type showCursorMsg (line 117) | type showCursorMsg struct
function EnableBracketedPaste (line 124) | func EnableBracketedPaste() Msg {
type enableBracketedPasteMsg (line 131) | type enableBracketedPasteMsg struct
function DisableBracketedPaste (line 138) | func DisableBracketedPaste() Msg {
type disableBracketedPasteMsg (line 145) | type disableBracketedPasteMsg struct
type enableReportFocusMsg (line 149) | type enableReportFocusMsg struct
function EnableReportFocus (line 153) | func EnableReportFocus() Msg {
type disableReportFocusMsg (line 159) | type disableReportFocusMsg struct
function DisableReportFocus (line 163) | func DisableReportFocus() Msg {
method EnterAltScreen (line 171) | func (p *Program) EnterAltScreen() {
method ExitAltScreen (line 182) | func (p *Program) ExitAltScreen() {
method EnableMouseCellMotion (line 194) | func (p *Program) EnableMouseCellMotion() {
method DisableMouseCellMotion (line 206) | func (p *Program) DisableMouseCellMotion() {
method EnableMouseAllMotion (line 219) | func (p *Program) EnableMouseAllMotion() {
method DisableMouseAllMotion (line 231) | func (p *Program) DisableMouseAllMotion() {
method SetWindowTitle (line 242) | func (p *Program) SetWindowTitle(title string) {
FILE: vendor/github.com/charmbracelet/bubbletea/signals_unix.go
method listenForResize (line 15) | func (p *Program) listenForResize(done chan struct{}) {
FILE: vendor/github.com/charmbracelet/bubbletea/signals_windows.go
method listenForResize (line 8) | func (p *Program) listenForResize(done chan struct{}) {
FILE: vendor/github.com/charmbracelet/bubbletea/standard_renderer.go
constant defaultFPS (line 18) | defaultFPS = 60
constant maxFPS (line 19) | maxFPS = 120
type standardRenderer (line 27) | type standardRenderer struct
method start (line 86) | func (r *standardRenderer) start() {
method stop (line 103) | func (r *standardRenderer) stop() {
method execute (line 127) | func (r *standardRenderer) execute(seq string) {
method kill (line 132) | func (r *standardRenderer) kill() {
method listen (line 147) | func (r *standardRenderer) listen() {
method flush (line 161) | func (r *standardRenderer) flush() {
method lastLinesRendered (line 294) | func (r *standardRenderer) lastLinesRendered() int {
method write (line 303) | func (r *standardRenderer) write(s string) {
method repaint (line 319) | func (r *standardRenderer) repaint() {
method clearScreen (line 324) | func (r *standardRenderer) clearScreen() {
method altScreen (line 334) | func (r *standardRenderer) altScreen() bool {
method enterAltScreen (line 341) | func (r *standardRenderer) enterAltScreen() {
method exitAltScreen (line 376) | func (r *standardRenderer) exitAltScreen() {
method showCursor (line 399) | func (r *standardRenderer) showCursor() {
method hideCursor (line 407) | func (r *standardRenderer) hideCursor() {
method enableMouseCellMotion (line 415) | func (r *standardRenderer) enableMouseCellMotion() {
method disableMouseCellMotion (line 422) | func (r *standardRenderer) disableMouseCellMotion() {
method enableMouseAllMotion (line 429) | func (r *standardRenderer) enableMouseAllMotion() {
method disableMouseAllMotion (line 436) | func (r *standardRenderer) disableMouseAllMotion() {
method enableMouseSGRMode (line 443) | func (r *standardRenderer) enableMouseSGRMode() {
method disableMouseSGRMode (line 450) | func (r *standardRenderer) disableMouseSGRMode() {
method enableBracketedPaste (line 457) | func (r *standardRenderer) enableBracketedPaste() {
method disableBracketedPaste (line 465) | func (r *standardRenderer) disableBracketedPaste() {
method bracketedPasteActive (line 473) | func (r *standardRenderer) bracketedPasteActive() bool {
method enableReportFocus (line 480) | func (r *standardRenderer) enableReportFocus() {
method disableReportFocus (line 488) | func (r *standardRenderer) disableReportFocus() {
method reportFocus (line 496) | func (r *standardRenderer) reportFocus() bool {
method setWindowTitle (line 504) | func (r *standardRenderer) setWindowTitle(title string) {
method setIgnoredLines (line 510) | func (r *standardRenderer) setIgnoredLines(from int, to int) {
method clearIgnoredLines (line 544) | func (r *standardRenderer) clearIgnoredLines() {
method insertTop (line 569) | func (r *standardRenderer) insertTop(lines []string, topBoundary, bott...
method insertBottom (line 599) | func (r *standardRenderer) insertBottom(lines []string, topBoundary, b...
method handleMessages (line 617) | func (r *standardRenderer) handleMessages(msg Msg) {
function newRenderer (line 65) | func newRenderer(out io.Writer, useANSICompressor bool, fps int) renderer {
type syncScrollAreaMsg (line 672) | type syncScrollAreaMsg struct
function SyncScrollArea (line 685) | func SyncScrollArea(lines []string, topBoundary int, bottomBoundary int)...
type clearScrollAreaMsg (line 695) | type clearScrollAreaMsg struct
function ClearScrollArea (line 703) | func ClearScrollArea() Msg {
type scrollUpMsg (line 707) | type scrollUpMsg struct
function ScrollUp (line 720) | func ScrollUp(newLines []string, topBoundary, bottomBoundary int) Cmd {
type scrollDownMsg (line 730) | type scrollDownMsg struct
function ScrollDown (line 743) | func ScrollDown(newLines []string, topBoundary, bottomBoundary int) Cmd {
type printLineMessage (line 753) | type printLineMessage struct
function Println (line 764) | func Println(args ...interface{}) Cmd {
function Printf (line 780) | func Printf(template string, args ...interface{}) Cmd {
FILE: vendor/github.com/charmbracelet/bubbletea/tea.go
type Msg (line 38) | type Msg interface
type Model (line 41) | type Model interface
type Cmd (line 62) | type Cmd
type inputType (line 64) | type inputType
method String (line 74) | func (i inputType) String() string {
constant defaultInput (line 67) | defaultInput inputType = iota
constant ttyInput (line 68) | ttyInput
constant customInput (line 69) | customInput
type startupOptions (line 86) | type startupOptions
method has (line 88) | func (s startupOptions) has(option startupOptions) bool {
constant withAltScreen (line 93) | withAltScreen startupOptions = 1 << iota
constant withMouseCellMotion (line 94) | withMouseCellMotion
constant withMouseAllMotion (line 95) | withMouseAllMotion
constant withANSICompressor (line 96) | withANSICompressor
constant withoutSignalHandler (line 97) | withoutSignalHandler
constant withoutCatchPanics (line 102) | withoutCatchPanics
constant withoutBracketedPaste (line 103) | withoutBracketedPaste
constant withReportFocus (line 104) | withReportFocus
type channelHandlers (line 110) | type channelHandlers
method add (line 114) | func (h *channelHandlers) add(ch chan struct{}) {
method shutdown (line 119) | func (h channelHandlers) shutdown() {
type Program (line 132) | type Program struct
method handleSignals (line 261) | func (p *Program) handleSignals() chan struct{} {
method handleResize (line 303) | func (p *Program) handleResize() chan struct{} {
method handleCommands (line 321) | func (p *Program) handleCommands(cmds chan Cmd) chan struct{} {
method disableMouse (line 358) | func (p *Program) disableMouse() {
method eventLoop (line 366) | func (p *Program) eventLoop(model Model, cmds chan Cmd) (Model, error) {
method Run (line 498) | func (p *Program) Run() (Model, error) {
method StartReturningModel (line 643) | func (p *Program) StartReturningModel() (Model, error) {
method Start (line 652) | func (p *Program) Start() error {
method Send (line 664) | func (p *Program) Send(msg Msg) {
method Quit (line 678) | func (p *Program) Quit() {
method Kill (line 685) | func (p *Program) Kill() {
method Wait (line 690) | func (p *Program) Wait() {
method shutdown (line 696) | func (p *Program) shutdown(kill bool) {
method recoverFromPanic (line 729) | func (p *Program) recoverFromPanic() {
method ReleaseTerminal (line 739) | func (p *Program) ReleaseTerminal() error {
method RestoreTerminal (line 760) | func (p *Program) RestoreTerminal() error {
method Println (line 798) | func (p *Program) Println(args ...interface{}) {
method Printf (line 812) | func (p *Program) Printf(template string, args ...interface{}) {
function Quit (line 189) | func Quit() Msg {
type QuitMsg (line 195) | type QuitMsg struct
function Suspend (line 198) | func Suspend() Msg {
type SuspendMsg (line 208) | type SuspendMsg struct
type ResumeMsg (line 212) | type ResumeMsg struct
type InterruptMsg (line 220) | type InterruptMsg struct
function Interrupt (line 224) | func Interrupt() Msg {
function NewProgram (line 229) | func NewProgram(model Model, opts ...ProgramOption) *Program {
FILE: vendor/github.com/charmbracelet/bubbletea/tea_init.go
function init (line 7) | func init() {
FILE: vendor/github.com/charmbracelet/bubbletea/tty.go
method suspend (line 13) | func (p *Program) suspend() {
method initTerminal (line 25) | func (p *Program) initTerminal() error {
method restoreTerminalState (line 41) | func (p *Program) restoreTerminalState() error {
method restoreInput (line 63) | func (p *Program) restoreInput() error {
method initCancelReader (line 78) | func (p *Program) initCancelReader() error {
method readLoop (line 91) | func (p *Program) readLoop() {
method waitForReadLoop (line 104) | func (p *Program) waitForReadLoop() {
method checkResize (line 116) | func (p *Program) checkResize() {
FILE: vendor/github.com/charmbracelet/bubbletea/tty_unix.go
method initInput (line 15) | func (p *Program) initInput() (err error) {
function openInputTTY (line 32) | func openInputTTY() (*os.File, error) {
constant suspendSupported (line 40) | suspendSupported = true
function suspendProcess (line 43) | func suspendProcess() {
FILE: vendor/github.com/charmbracelet/bubbletea/tty_windows.go
method initInput (line 14) | func (p *Program) initInput() (err error) {
function openInputTTY (line 58) | func openInputTTY() (*os.File, error) {
constant suspendSupported (line 66) | suspendSupported = false
function suspendProcess (line 68) | func suspendProcess() {}
FILE: vendor/github.com/charmbracelet/lipgloss/align.go
function alignTextHorizontal (line 13) | func alignTextHorizontal(str string, pos Position, width int, style *ter...
function alignTextVertical (line 62) | func alignTextVertical(str string, pos Position, height int, _ *termenv....
FILE: vendor/github.com/charmbracelet/lipgloss/ansi_unix.go
function enableLegacyWindowsANSI (line 7) | func enableLegacyWindowsANSI() {}
FILE: vendor/github.com/charmbracelet/lipgloss/ansi_windows.go
function enableLegacyWindowsANSI (line 18) | func enableLegacyWindowsANSI() {
FILE: vendor/github.com/charmbracelet/lipgloss/borders.go
type Border (line 13) | type Border struct
method GetTopSize (line 32) | func (b Border) GetTopSize() int {
method GetRightSize (line 39) | func (b Border) GetRightSize() int {
method GetBottomSize (line 46) | func (b Border) GetBottomSize() int {
method GetLeftSize (line 53) | func (b Border) GetLeftSize() int {
function getBorderEdgeWidth (line 57) | func getBorderEdgeWidth(borderParts ...string) (maxWidth int) {
function NormalBorder (line 186) | func NormalBorder() Border {
function RoundedBorder (line 191) | func RoundedBorder() Border {
function BlockBorder (line 196) | func BlockBorder() Border {
function OuterHalfBlockBorder (line 201) | func OuterHalfBlockBorder() Border {
function InnerHalfBlockBorder (line 206) | func InnerHalfBlockBorder() Border {
function ThickBorder (line 212) | func ThickBorder() Border {
function DoubleBorder (line 217) | func DoubleBorder() Border {
function HiddenBorder (line 225) | func HiddenBorder() Border {
method applyBorder (line 229) | func (s Style) applyBorder(str string) string {
function renderHorizontalEdge (line 378) | func renderHorizontalEdge(left, middle, right string, width int) string {
method styleBorder (line 405) | func (s Style) styleBorder(border string, fg, bg TerminalColor) string {
function maxRuneWidth (line 422) | func maxRuneWidth(str string) int {
function getFirstRuneAsString (line 437) | func getFirstRuneAsString(str string) string {
FILE: vendor/github.com/charmbracelet/lipgloss/color.go
type TerminalColor (line 10) | type TerminalColor interface
type NoColor (line 24) | type NoColor struct
method color (line 26) | func (NoColor) color(*Renderer) termenv.Color {
method RGBA (line 37) | func (n NoColor) RGBA() (r, g, b, a uint32) {
type Color (line 45) | type Color
method color (line 47) | func (c Color) color(r *Renderer) termenv.Color {
method RGBA (line 57) | func (c Color) RGBA() (r, g, b, a uint32) {
type ANSIColor (line 70) | type ANSIColor
method color (line 72) | func (ac ANSIColor) color(r *Renderer) termenv.Color {
method RGBA (line 82) | func (ac ANSIColor) RGBA() (r, g, b, a uint32) {
type AdaptiveColor (line 94) | type AdaptiveColor struct
method color (line 99) | func (ac AdaptiveColor) color(r *Renderer) termenv.Color {
method RGBA (line 112) | func (ac AdaptiveColor) RGBA() (r, g, b, a uint32) {
type CompleteColor (line 118) | type CompleteColor struct
method color (line 124) | func (c CompleteColor) color(r *Renderer) termenv.Color {
method RGBA (line 145) | func (c CompleteColor) RGBA() (r, g, b, a uint32) {
type CompleteAdaptiveColor (line 152) | type CompleteAdaptiveColor struct
method color (line 157) | func (cac CompleteAdaptiveColor) color(r *Renderer) termenv.Color {
method RGBA (line 170) | func (cac CompleteAdaptiveColor) RGBA() (r, g, b, a uint32) {
FILE: vendor/github.com/charmbracelet/lipgloss/get.go
method GetBold (line 10) | func (s Style) GetBold() bool {
method GetItalic (line 16) | func (s Style) GetItalic() bool {
method GetUnderline (line 22) | func (s Style) GetUnderline() bool {
method GetStrikethrough (line 28) | func (s Style) GetStrikethrough() bool {
method GetReverse (line 34) | func (s Style) GetReverse() bool {
method GetBlink (line 40) | func (s Style) GetBlink() bool {
method GetFaint (line 46) | func (s Style) GetFaint() bool {
method GetForeground (line 52) | func (s Style) GetForeground() TerminalColor {
method GetBackground (line 58) | func (s Style) GetBackground() TerminalColor {
method GetWidth (line 64) | func (s Style) GetWidth() int {
method GetHeight (line 70) | func (s Style) GetHeight() int {
method GetAlign (line 76) | func (s Style) GetAlign() Position {
method GetAlignHorizontal (line 86) | func (s Style) GetAlignHorizontal() Position {
method GetAlignVertical (line 96) | func (s Style) GetAlignVertical() Position {
method GetPadding (line 106) | func (s Style) GetPadding() (top, right, bottom, left int) {
method GetPaddingTop (line 115) | func (s Style) GetPaddingTop() int {
method GetPaddingRight (line 121) | func (s Style) GetPaddingRight() int {
method GetPaddingBottom (line 127) | func (s Style) GetPaddingBottom() int {
method GetPaddingLeft (line 133) | func (s Style) GetPaddingLeft() int {
method GetHorizontalPadding (line 139) | func (s Style) GetHorizontalPadding() int {
method GetVerticalPadding (line 145) | func (s Style) GetVerticalPadding() int {
method GetColorWhitespace (line 151) | func (s Style) GetColorWhitespace() bool {
method GetMargin (line 157) | func (s Style) GetMargin() (top, right, bottom, left int) {
method GetMarginTop (line 166) | func (s Style) GetMarginTop() int {
method GetMarginRight (line 172) | func (s Style) GetMarginRight() int {
method GetMarginBottom (line 178) | func (s Style) GetMarginBottom() int {
method GetMarginLeft (line 184) | func (s Style) GetMarginLeft() int {
method GetHorizontalMargins (line 190) | func (s Style) GetHorizontalMargins() int {
method GetVerticalMargins (line 196) | func (s Style) GetVerticalMargins() int {
method GetBorder (line 204) | func (s Style) GetBorder() (b Border, top, right, bottom, left bool) {
method GetBorderStyle (line 214) | func (s Style) GetBorderStyle() Border {
method GetBorderTop (line 220) | func (s Style) GetBorderTop() bool {
method GetBorderRight (line 226) | func (s Style) GetBorderRight() bool {
method GetBorderBottom (line 232) | func (s Style) GetBorderBottom() bool {
method GetBorderLeft (line 238) | func (s Style) GetBorderLeft() bool {
method GetBorderTopForeground (line 244) | func (s Style) GetBorderTopForeground() TerminalColor {
method GetBorderRightForeground (line 250) | func (s Style) GetBorderRightForeground() TerminalColor {
method GetBorderBottomForeground (line 256) | func (s Style) GetBorderBottomForeground() TerminalColor {
method GetBorderLeftForeground (line 262) | func (s Style) GetBorderLeftForeground() TerminalColor {
method GetBorderTopBackground (line 268) | func (s Style) GetBorderTopBackground() TerminalColor {
method GetBorderRightBackground (line 274) | func (s Style) GetBorderRightBackground() TerminalColor {
method GetBorderBottomBackground (line 280) | func (s Style) GetBorderBottomBackground() TerminalColor {
method GetBorderLeftBackground (line 286) | func (s Style) GetBorderLeftBackground() TerminalColor {
method GetBorderTopWidth (line 295) | func (s Style) GetBorderTopWidth() int {
method GetBorderTopSize (line 302) | func (s Style) GetBorderTopSize() int {
method GetBorderLeftSize (line 312) | func (s Style) GetBorderLeftSize() int {
method GetBorderBottomSize (line 322) | func (s Style) GetBorderBottomSize() int {
method GetBorderRightSize (line 332) | func (s Style) GetBorderRightSize() int {
method GetHorizontalBorderSize (line 342) | func (s Style) GetHorizontalBorderSize() int {
method GetVerticalBorderSize (line 349) | func (s Style) GetVerticalBorderSize() int {
method GetInline (line 355) | func (s Style) GetInline() bool {
method GetMaxWidth (line 361) | func (s Style) GetMaxWidth() int {
method GetMaxHeight (line 367) | func (s Style) GetMaxHeight() int {
method GetTabWidth (line 373) | func (s Style) GetTabWidth() int {
method GetUnderlineSpaces (line 379) | func (s Style) GetUnderlineSpaces() bool {
method GetStrikethroughSpaces (line 385) | func (s Style) GetStrikethroughSpaces() bool {
method GetHorizontalFrameSize (line 393) | func (s Style) GetHorizontalFrameSize() int {
method GetVerticalFrameSize (line 401) | func (s Style) GetVerticalFrameSize() int {
method GetFrameSize (line 407) | func (s Style) GetFrameSize() (x, y int) {
method GetTransform (line 413) | func (s Style) GetTransform() func(string) string {
method isSet (line 418) | func (s Style) isSet(k propKey) bool {
method getAsBool (line 422) | func (s Style) getAsBool(k propKey, defaultVal bool) bool {
method getAsColor (line 429) | func (s Style) getAsColor(k propKey) TerminalColor {
method getAsInt (line 467) | func (s Style) getAsInt(k propKey) int {
method getAsPosition (line 502) | func (s Style) getAsPosition(k propKey) Position {
method getBorderStyle (line 515) | func (s Style) getBorderStyle() Border {
method getAsTransform (line 522) | func (s Style) getAsTransform(propKey) func(string) string {
function getLines (line 531) | func getLines(s string) (lines []string, widest int) {
FILE: vendor/github.com/charmbracelet/lipgloss/join.go
function JoinHorizontal (line 28) | func JoinHorizontal(pos Position, strs ...string) string {
function JoinVertical (line 116) | func JoinVertical(pos Position, strs ...string) string {
FILE: vendor/github.com/charmbracelet/lipgloss/position.go
type Position (line 19) | type Position
method value (line 21) | func (p Position) value() float64 {
constant Top (line 27) | Top Position = 0.0
constant Bottom (line 28) | Bottom Position = 1.0
constant Center (line 29) | Center Position = 0.5
constant Left (line 30) | Left Position = 0.0
constant Right (line 31) | Right Position = 1.0
function Place (line 36) | func Place(width, height int, hPos, vPos Position, str string, opts ...W...
method Place (line 42) | func (r *Renderer) Place(width, height int, hPos, vPos Position, str str...
function PlaceHorizontal (line 49) | func PlaceHorizontal(width int, pos Position, str string, opts ...Whites...
method PlaceHorizontal (line 56) | func (r *Renderer) PlaceHorizontal(width int, pos Position, str string, ...
function PlaceVertical (line 103) | func PlaceVertical(height int, pos Position, str string, opts ...Whitesp...
method PlaceVertical (line 110) | func (r *Renderer) PlaceVertical(height int, pos Position, str string, o...
FILE: vendor/github.com/charmbracelet/lipgloss/renderer.go
type Renderer (line 17) | type Renderer struct
method Output (line 52) | func (r *Renderer) Output() *termenv.Output {
method SetOutput (line 59) | func (r *Renderer) SetOutput(o *termenv.Output) {
method ColorProfile (line 66) | func (r *Renderer) ColorProfile() termenv.Profile {
method SetColorProfile (line 102) | func (r *Renderer) SetColorProfile(p termenv.Profile) {
method HasDarkBackground (line 138) | func (r *Renderer) HasDarkBackground() bool {
method SetHasDarkBackground (line 175) | func (r *Renderer) SetHasDarkBackground(b bool) {
function DefaultRenderer (line 32) | func DefaultRenderer() *Renderer {
function SetDefaultRenderer (line 37) | func SetDefaultRenderer(r *Renderer) {
function NewRenderer (line 44) | func NewRenderer(w io.Writer, opts ...termenv.OutputOption) *Renderer {
function ColorProfile (line 82) | func ColorProfile() termenv.Profile {
function SetColorProfile (line 126) | func SetColorProfile(p termenv.Profile) {
function HasDarkBackground (line 131) | func HasDarkBackground() bool {
function SetHasDarkBackground (line 162) | func SetHasDarkBackground(b bool) {
FILE: vendor/github.com/charmbracelet/lipgloss/runes.go
function StyleRunes (line 10) | func StyleRunes(str string, indices []int, matched, unmatched Style) str...
FILE: vendor/github.com/charmbracelet/lipgloss/set.go
method set (line 4) | func (s *Style) set(key propKey, value interface{}) {
method setFrom (line 90) | func (s *Style) setFrom(key propKey, i Style) {
function colorOrNil (line 154) | func colorOrNil(c interface{}) TerminalColor {
method Bold (line 162) | func (s Style) Bold(v bool) Style {
method Italic (line 169) | func (s Style) Italic(v bool) Style {
method Underline (line 177) | func (s Style) Underline(v bool) Style {
method Strikethrough (line 185) | func (s Style) Strikethrough(v bool) Style {
method Reverse (line 191) | func (s Style) Reverse(v bool) Style {
method Blink (line 197) | func (s Style) Blink(v bool) Style {
method Faint (line 203) | func (s Style) Faint(v bool) Style {
method Foreground (line 215) | func (s Style) Foreground(c TerminalColor) Style {
method Background (line 221) | func (s Style) Background(c TerminalColor) Style {
method Width (line 228) | func (s Style) Width(i int) Style {
method Height (line 236) | func (s Style) Height(i int) Style {
method Align (line 247) | func (s Style) Align(p ...Position) Style {
method AlignHorizontal (line 258) | func (s Style) AlignHorizontal(p Position) Style {
method AlignVertical (line 264) | func (s Style) AlignVertical(p Position) Style {
method Padding (line 283) | func (s Style) Padding(i ...int) Style {
method PaddingLeft (line 297) | func (s Style) PaddingLeft(i int) Style {
method PaddingRight (line 303) | func (s Style) PaddingRight(i int) Style {
method PaddingTop (line 309) | func (s Style) PaddingTop(i int) Style {
method PaddingBottom (line 315) | func (s Style) PaddingBottom(i int) Style {
method ColorWhitespace (line 326) | func (s Style) ColorWhitespace(v bool) Style {
method Margin (line 345) | func (s Style) Margin(i ...int) Style {
method MarginLeft (line 359) | func (s Style) MarginLeft(i int) Style {
method MarginRight (line 365) | func (s Style) MarginRight(i int) Style {
method MarginTop (line 371) | func (s Style) MarginTop(i int) Style {
method MarginBottom (line 377) | func (s Style) MarginBottom(i int) Style {
method MarginBackground (line 385) | func (s Style) MarginBackground(c TerminalColor) Style {
method Border (line 413) | func (s Style) Border(b Border, sides ...bool) Style {
method BorderStyle (line 446) | func (s Style) BorderStyle(b Border) Style {
method BorderTop (line 452) | func (s Style) BorderTop(v bool) Style {
method BorderRight (line 458) | func (s Style) BorderRight(v bool) Style {
method BorderBottom (line 464) | func (s Style) BorderBottom(v bool) Style {
method BorderLeft (line 470) | func (s Style) BorderLeft(v bool) Style {
method BorderForeground (line 490) | func (s Style) BorderForeground(c ...TerminalColor) Style {
method BorderTopForeground (line 509) | func (s Style) BorderTopForeground(c TerminalColor) Style {
method BorderRightForeground (line 516) | func (s Style) BorderRightForeground(c TerminalColor) Style {
method BorderBottomForeground (line 523) | func (s Style) BorderBottomForeground(c TerminalColor) Style {
method BorderLeftForeground (line 530) | func (s Style) BorderLeftForeground(c TerminalColor) Style {
method BorderBackground (line 550) | func (s Style) BorderBackground(c ...TerminalColor) Style {
method BorderTopBackground (line 569) | func (s Style) BorderTopBackground(c TerminalColor) Style {
method BorderRightBackground (line 575) | func (s Style) BorderRightBackground(c TerminalColor) Style {
method BorderBottomBackground (line 582) | func (s Style) BorderBottomBackground(c TerminalColor) Style {
method BorderLeftBackground (line 589) | func (s Style) BorderLeftBackground(c TerminalColor) Style {
method Inline (line 607) | func (s Style) Inline(v bool) Style {
method MaxWidth (line 625) | func (s Style) MaxWidth(n int) Style {
method MaxHeight (line 637) | func (s Style) MaxHeight(n int) Style {
constant NoTabConversion (line 645) | NoTabConversion = -1
method TabWidth (line 652) | func (s Style) TabWidth(n int) Style {
method UnderlineSpaces (line 663) | func (s Style) UnderlineSpaces(v bool) Style {
method StrikethroughSpaces (line 671) | func (s Style) StrikethroughSpaces(v bool) Style {
method Transform (line 683) | func (s Style) Transform(fn func(string) string) Style {
method Renderer (line 690) | func (s Style) Renderer(r *Renderer) Style {
function whichSidesInt (line 705) | func whichSidesInt(i ...int) (top, right, bottom, left int, ok bool) {
function whichSidesBool (line 738) | func whichSidesBool(i ...bool) (top, right, bottom, left bool, ok bool) {
function whichSidesColor (line 771) | func whichSidesColor(i ...TerminalColor) (top, right, bottom, left Termi...
FILE: vendor/github.com/charmbracelet/lipgloss/size.go
function Width (line 15) | func Width(str string) (width int) {
function Height (line 30) | func Height(str string) int {
function Size (line 37) | func Size(str string) (width, height int) {
FILE: vendor/github.com/charmbracelet/lipgloss/style.go
constant tabWidthDefault (line 11) | tabWidthDefault = 4
type propKey (line 14) | type propKey
constant boldKey (line 19) | boldKey propKey = 1 << iota
constant italicKey (line 20) | italicKey
constant underlineKey (line 21) | underlineKey
constant strikethroughKey (line 22) | strikethroughKey
constant reverseKey (line 23) | reverseKey
constant blinkKey (line 24) | blinkKey
constant faintKey (line 25) | faintKey
constant underlineSpacesKey (line 26) | underlineSpacesKey
constant strikethroughSpacesKey (line 27) | strikethroughSpacesKey
constant colorWhitespaceKey (line 28) | colorWhitespaceKey
constant foregroundKey (line 31) | foregroundKey
constant backgroundKey (line 32) | backgroundKey
constant widthKey (line 33) | widthKey
constant heightKey (line 34) | heightKey
constant alignHorizontalKey (line 35) | alignHorizontalKey
constant alignVerticalKey (line 36) | alignVerticalKey
constant paddingTopKey (line 39) | paddingTopKey
constant paddingRightKey (line 40) | paddingRightKey
constant paddingBottomKey (line 41) | paddingBottomKey
constant paddingLeftKey (line 42) | paddingLeftKey
constant marginTopKey (line 45) | marginTopKey
constant marginRightKey (line 46) | marginRightKey
constant marginBottomKey (line 47) | marginBottomKey
constant marginLeftKey (line 48) | marginLeftKey
constant marginBackgroundKey (line 49) | marginBackgroundKey
constant borderStyleKey (line 52) | borderStyleKey
constant borderTopKey (line 55) | borderTopKey
constant borderRightKey (line 56) | borderRightKey
constant borderBottomKey (line 57) | borderBottomKey
constant borderLeftKey (line 58) | borderLeftKey
constant borderTopForegroundKey (line 61) | borderTopForegroundKey
constant borderRightForegroundKey (line 62) | borderRightForegroundKey
constant borderBottomForegroundKey (line 63) | borderBottomForegroundKey
constant borderLeftForegroundKey (line 64) | borderLeftForegroundKey
constant borderTopBackgroundKey (line 67) | borderTopBackgroundKey
constant borderRightBackgroundKey (line 68) | borderRightBackgroundKey
constant borderBottomBackgroundKey (line 69) | borderBottomBackgroundKey
constant borderLeftBackgroundKey (line 70) | borderLeftBackgroundKey
constant inlineKey (line 72) | inlineKey
constant maxWidthKey (line 73) | maxWidthKey
constant maxHeightKey (line 74) | maxHeightKey
constant tabWidthKey (line 75) | tabWidthKey
constant transformKey (line 77) | transformKey
type props (line 81) | type props
method set (line 84) | func (p props) set(k propKey) props {
method unset (line 89) | func (p props) unset(k propKey) props {
method has (line 94) | func (p props) has(k propKey) bool {
function NewStyle (line 102) | func NewStyle() Style {
method NewStyle (line 110) | func (r *Renderer) NewStyle() Style {
type Style (line 116) | type Style struct
method SetString (line 173) | func (s Style) SetString(strs ...string) Style {
method Value (line 179) | func (s Style) Value() string {
method String (line 186) | func (s Style) String() string {
method Copy (line 194) | func (s Style) Copy() Style {
method Inherit (line 203) | func (s Style) Inherit(i Style) Style {
method Render (line 233) | func (s Style) Render(strs ...string) string {
method maybeConvertTabs (line 471) | func (s Style) maybeConvertTabs(str string) string {
method applyMargins (line 486) | func (s Style) applyMargins(str string, inline bool) string {
function joinString (line 164) | func joinString(strs ...string) string {
function padLeft (line 522) | func padLeft(str string, n int, style *termenv.Style) string {
function padRight (line 527) | func padRight(str string, n int, style *termenv.Style) string {
function pad (line 534) | func pad(str string, n int, style *termenv.Style) string {
function max (line 567) | func max(a, b int) int { //nolint:unparam,predeclared
function min (line 574) | func min(a, b int) int { //nolint:predeclared
function abs (line 581) | func abs(a int) int {
FILE: vendor/github.com/charmbracelet/lipgloss/unset.go
method unset (line 4) | func (s *Style) unset(key propKey) {
method UnsetBold (line 9) | func (s Style) UnsetBold() Style {
method UnsetItalic (line 15) | func (s Style) UnsetItalic() Style {
method UnsetUnderline (line 21) | func (s Style) UnsetUnderline() Style {
method UnsetStrikethrough (line 27) | func (s Style) UnsetStrikethrough() Style {
method UnsetReverse (line 33) | func (s Style) UnsetReverse() Style {
method UnsetBlink (line 39) | func (s Style) UnsetBlink() Style {
method UnsetFaint (line 45) | func (s Style) UnsetFaint() Style {
method UnsetForeground (line 51) | func (s Style) UnsetForeground() Style {
method UnsetBackground (line 57) | func (s Style) UnsetBackground() Style {
method UnsetWidth (line 63) | func (s Style) UnsetWidth() Style {
method UnsetHeight (line 69) | func (s Style) UnsetHeight() Style {
method UnsetAlign (line 75) | func (s Style) UnsetAlign() Style {
method UnsetAlignHorizontal (line 82) | func (s Style) UnsetAlignHorizontal() Style {
method UnsetAlignVertical (line 88) | func (s Style) UnsetAlignVertical() Style {
method UnsetPadding (line 94) | func (s Style) UnsetPadding() Style {
method UnsetPaddingLeft (line 103) | func (s Style) UnsetPaddingLeft() Style {
method UnsetPaddingRight (line 109) | func (s Style) UnsetPaddingRight() Style {
method UnsetPaddingTop (line 115) | func (s Style) UnsetPaddingTop() Style {
method UnsetPaddingBottom (line 121) | func (s Style) UnsetPaddingBottom() Style {
method UnsetColorWhitespace (line 127) | func (s Style) UnsetColorWhitespace() Style {
method UnsetMargins (line 133) | func (s Style) UnsetMargins() Style {
method UnsetMarginLeft (line 142) | func (s Style) UnsetMarginLeft() Style {
method UnsetMarginRight (line 148) | func (s Style) UnsetMarginRight() Style {
method UnsetMarginTop (line 154) | func (s Style) UnsetMarginTop() Style {
method UnsetMarginBottom (line 160) | func (s Style) UnsetMarginBottom() Style {
method UnsetMarginBackground (line 168) | func (s Style) UnsetMarginBackground() Style {
method UnsetBorderStyle (line 174) | func (s Style) UnsetBorderStyle() Style {
method UnsetBorderTop (line 180) | func (s Style) UnsetBorderTop() Style {
method UnsetBorderRight (line 186) | func (s Style) UnsetBorderRight() Style {
method UnsetBorderBottom (line 192) | func (s Style) UnsetBorderBottom() Style {
method UnsetBorderLeft (line 198) | func (s Style) UnsetBorderLeft() Style {
method UnsetBorderForeground (line 204) | func (s Style) UnsetBorderForeground() Style {
method UnsetBorderTopForeground (line 214) | func (s Style) UnsetBorderTopForeground() Style {
method UnsetBorderRightForeground (line 221) | func (s Style) UnsetBorderRightForeground() Style {
method UnsetBorderBottomForeground (line 228) | func (s Style) UnsetBorderBottomForeground() Style {
method UnsetBorderLeftForeground (line 235) | func (s Style) UnsetBorderLeftForeground() Style {
method UnsetBorderBackground (line 242) | func (s Style) UnsetBorderBackground() Style {
method UnsetBorderTopBackgroundColor (line 254) | func (s Style) UnsetBorderTopBackgroundColor() Style {
method UnsetBorderTopBackground (line 260) | func (s Style) UnsetBorderTopBackground() Style {
method UnsetBorderRightBackground (line 267) | func (s Style) UnsetBorderRightBackground() Style {
method UnsetBorderBottomBackground (line 274) | func (s Style) UnsetBorderBottomBackground() Style {
method UnsetBorderLeftBackground (line 280) | func (s Style) UnsetBorderLeftBackground() Style {
method UnsetInline (line 286) | func (s Style) UnsetInline() Style {
method UnsetMaxWidth (line 292) | func (s Style) UnsetMaxWidth() Style {
method UnsetMaxHeight (line 298) | func (s Style) UnsetMaxHeight() Style {
method UnsetTabWidth (line 304) | func (s Style) UnsetTabWidth() Style {
method UnsetUnderlineSpaces (line 310) | func (s Style) UnsetUnderlineSpaces() Style {
method UnsetStrikethroughSpaces (line 316) | func (s Style) UnsetStrikethroughSpaces() Style {
method UnsetTransform (line 322) | func (s Style) UnsetTransform() Style {
method UnsetString (line 328) | func (s Style) UnsetString() Style {
FILE: vendor/github.com/charmbracelet/lipgloss/whitespace.go
type whitespace (line 11) | type whitespace struct
method render (line 32) | func (w whitespace) render(width int) string {
function newWhitespace (line 20) | func newWhitespace(r *Renderer, opts ...WhitespaceOption) *whitespace {
type WhitespaceOption (line 62) | type WhitespaceOption
function WithWhitespaceForeground (line 65) | func WithWhitespaceForeground(c TerminalColor) WhitespaceOption {
function WithWhitespaceBackground (line 72) | func WithWhitespaceBackground(c TerminalColor) WhitespaceOption {
function WithWhitespaceChars (line 79) | func WithWhitespaceChars(s string) WhitespaceOption {
FILE: vendor/github.com/charmbracelet/x/ansi/ansi.go
function Execute (line 9) | func Execute(w io.Writer, s string) (int, error) {
FILE: vendor/github.com/charmbracelet/x/ansi/ascii.go
constant SP (line 5) | SP = 0x20
constant DEL (line 7) | DEL = 0x7F
FILE: vendor/github.com/charmbracelet/x/ansi/background.go
type Colorizer (line 9) | type Colorizer interface
type HexColorizer (line 15) | type HexColorizer struct
method String (line 21) | func (h HexColorizer) String() string {
type XRGBColorizer (line 37) | type XRGBColorizer struct
method String (line 43) | func (x XRGBColorizer) String() string {
type XRGBAColorizer (line 56) | type XRGBAColorizer struct
method String (line 62) | func (x XRGBAColorizer) String() string {
function SetForegroundColor (line 80) | func SetForegroundColor(c color.Color) string {
constant RequestForegroundColor (line 97) | RequestForegroundColor = "\x1b]10;?\x07"
constant ResetForegroundColor (line 103) | ResetForegroundColor = "\x1b]110\x07"
function SetBackgroundColor (line 114) | func SetBackgroundColor(c color.Color) string {
constant RequestBackgroundColor (line 131) | RequestBackgroundColor = "\x1b]11;?\x07"
constant ResetBackgroundColor (line 137) | ResetBackgroundColor = "\x1b]111\x07"
function SetCursorColor (line 147) | func SetCursorColor(c color.Color) string {
constant RequestCursorColor (line 164) | RequestCursorColor = "\x1b]12;?\x07"
constant ResetCursorColor (line 169) | ResetCursorColor = "\x1b]112\x07"
FILE: vendor/github.com/charmbracelet/x/ansi/c0.go
constant NUL (line 9) | NUL = 0x00
constant SOH (line 11) | SOH = 0x01
constant STX (line 13) | STX = 0x02
constant ETX (line 15) | ETX = 0x03
constant EOT (line 17) | EOT = 0x04
constant ENQ (line 19) | ENQ = 0x05
constant ACK (line 21) | ACK = 0x06
constant BEL (line 23) | BEL = 0x07
constant BS (line 25) | BS = 0x08
constant HT (line 27) | HT = 0x09
constant LF (line 29) | LF = 0x0A
constant VT (line 31) | VT = 0x0B
constant FF (line 33) | FF = 0x0C
constant CR (line 35) | CR = 0x0D
constant SO (line 37) | SO = 0x0E
constant SI (line 39) | SI = 0x0F
constant DLE (line 41) | DLE = 0x10
constant DC1 (line 43) | DC1 = 0x11
constant DC2 (line 45) | DC2 = 0x12
constant DC3 (line 47) | DC3 = 0x13
constant DC4 (line 49) | DC4 = 0x14
constant NAK (line 51) | NAK = 0x15
constant SYN (line 53) | SYN = 0x16
constant ETB (line 55) | ETB = 0x17
constant CAN (line 57) | CAN = 0x18
constant EM (line 59) | EM = 0x19
constant SUB (line 61) | SUB = 0x1A
constant ESC (line 63) | ESC = 0x1B
constant FS (line 65) | FS = 0x1C
constant GS (line 67) | GS = 0x1D
constant RS (line 69) | RS = 0x1E
constant US (line 71) | US = 0x1F
constant LS0 (line 75) | LS0 = SI
constant LS1 (line 78) | LS1 = SO
FILE: vendor/github.com/charmbracelet/x/ansi/c1.go
constant PAD (line 9) | PAD = 0x80
constant HOP (line 11) | HOP = 0x81
constant BPH (line 13) | BPH = 0x82
constant NBH (line 15) | NBH = 0x83
constant IND (line 17) | IND = 0x84
constant NEL (line 19) | NEL = 0x85
constant SSA (line 21) | SSA = 0x86
constant ESA (line 23) | ESA = 0x87
constant HTS (line 25) | HTS = 0x88
constant HTJ (line 27) | HTJ = 0x89
constant VTS (line 29) | VTS = 0x8A
constant PLD (line 31) | PLD = 0x8B
constant PLU (line 33) | PLU = 0x8C
constant RI (line 35) | RI = 0x8D
constant SS2 (line 37) | SS2 = 0x8E
constant SS3 (line 39) | SS3 = 0x8F
constant DCS (line 41) | DCS = 0x90
constant PU1 (line 43) | PU1 = 0x91
constant PU2 (line 45) | PU2 = 0x92
constant STS (line 47) | STS = 0x93
constant CCH (line 49) | CCH = 0x94
constant MW (line 51) | MW = 0x95
constant SPA (line 53) | SPA = 0x96
constant EPA (line 55) | EPA = 0x97
constant SOS (line 57) | SOS = 0x98
constant SGCI (line 59) | SGCI = 0x99
constant SCI (line 61) | SCI = 0x9A
constant CSI (line 63) | CSI = 0x9B
constant ST (line 65) | ST = 0x9C
constant OSC (line 67) | OSC = 0x9D
constant PM (line 69) | PM = 0x9E
constant APC (line 71) | APC = 0x9F
FILE: vendor/github.com/charmbracelet/x/ansi/charset.go
function SelectCharacterSet (line 33) | func SelectCharacterSet(gset byte, charset byte) string {
function SCS (line 38) | func SCS(gset byte, charset byte) string {
constant LS1R (line 43) | LS1R = "\x1b~"
constant LS2 (line 46) | LS2 = "\x1bn"
constant LS2R (line 49) | LS2R = "\x1b}"
constant LS3 (line 52) | LS3 = "\x1bo"
constant LS3R (line 55) | LS3R = "\x1b|"
FILE: vendor/github.com/charmbracelet/x/ansi/clipboard.go
constant SystemClipboard (line 7) | SystemClipboard = 'c'
constant PrimaryClipboard (line 8) | PrimaryClipboard = 'p'
function SetClipboard (line 20) | func SetClipboard(c byte, d string) string {
function SetSystemClipboard (line 30) | func SetSystemClipboard(d string) string {
function SetPrimaryClipboard (line 37) | func SetPrimaryClipboard(d string) string {
function ResetClipboard (line 46) | func ResetClipboard(c byte) string {
constant ResetSystemClipboard (line 53) | ResetSystemClipboard = "\x1b]52;c;\x07"
constant ResetPrimaryClipboard (line 58) | ResetPrimaryClipboard = "\x1b]52;p;\x07"
function RequestClipboard (line 63) | func RequestClipboard(c byte) string {
constant RequestSystemClipboard (line 70) | RequestSystemClipboard = "\x1b]52;c;?\x07"
constant RequestPrimaryClipboard (line 75) | RequestPrimaryClipboard = "\x1b]52;p;?\x07"
FILE: vendor/github.com/charmbracelet/x/ansi/color.go
type Color (line 36) | type Color interface
type BasicColor (line 41) | type BasicColor
method RGBA (line 97) | func (c BasicColor) RGBA() (uint32, uint32, uint32, uint32) {
constant Black (line 47) | Black BasicColor = iota
constant Red (line 50) | Red
constant Green (line 53) | Green
constant Yellow (line 56) | Yellow
constant Blue (line 59) | Blue
constant Magenta (line 62) | Magenta
constant Cyan (line 65) | Cyan
constant White (line 68) | White
constant BrightBlack (line 71) | BrightBlack
constant BrightRed (line 74) | BrightRed
constant BrightGreen (line 77) | BrightGreen
constant BrightYellow (line 80) | BrightYellow
constant BrightBlue (line 83) | BrightBlue
constant BrightMagenta (line 86) | BrightMagenta
constant BrightCyan (line 89) | BrightCyan
constant BrightWhite (line 92) | BrightWhite
type ExtendedColor (line 108) | type ExtendedColor
method RGBA (line 114) | func (c ExtendedColor) RGBA() (uint32, uint32, uint32, uint32) {
type TrueColor (line 125) | type TrueColor
method RGBA (line 131) | func (c TrueColor) RGBA() (uint32, uint32, uint32, uint32) {
function ansiToRGB (line 139) | func ansiToRGB(ansi uint32) (uint32, uint32, uint32) {
function hexToRGB (line 180) | func hexToRGB(hex uint32) (uint32, uint32, uint32) {
function toRGBA (line 191) | func toRGBA(r, g, b uint32) (uint32, uint32, uint32, uint32) {
FILE: vendor/github.com/charmbracelet/x/ansi/ctrl.go
constant RequestNameVersion (line 17) | RequestNameVersion = "\x1b[>q"
constant XTVERSION (line 18) | XTVERSION = RequestNameVersion
constant RequestXTVersion (line 29) | RequestXTVersion = RequestNameVersion
function PrimaryDeviceAttributes (line 42) | func PrimaryDeviceAttributes(attrs ...int) string {
function DA1 (line 57) | func DA1(attrs ...int) string {
constant RequestPrimaryDeviceAttributes (line 67) | RequestPrimaryDeviceAttributes = "\x1b[c"
function SecondaryDeviceAttributes (line 77) | func SecondaryDeviceAttributes(attrs ...int) string {
function DA2 (line 90) | func DA2(attrs ...int) string {
constant RequestSecondaryDeviceAttributes (line 100) | RequestSecondaryDeviceAttributes = "\x1b[>c"
function TertiaryDeviceAttributes (line 115) | func TertiaryDeviceAttributes(unitID string) string {
function DA3 (line 127) | func DA3(unitID string) string {
constant RequestTertiaryDeviceAttributes (line 137) | RequestTertiaryDeviceAttributes = "\x1b[=c"
FILE: vendor/github.com/charmbracelet/x/ansi/cursor.go
constant SaveCursor (line 12) | SaveCursor = "\x1b7"
constant DECSC (line 13) | DECSC = SaveCursor
constant RestoreCursor (line 23) | RestoreCursor = "\x1b8"
constant DECRC (line 24) | DECRC = RestoreCursor
constant RequestCursorPosition (line 41) | RequestCursorPosition = "\x1b[6n"
constant RequestExtendedCursorPosition (line 58) | RequestExtendedCursorPosition = "\x1b[?6n"
function CursorUp (line 65) | func CursorUp(n int) string {
function CUU (line 74) | func CUU(n int) string {
constant CUU1 (line 79) | CUU1 = "\x1b[A"
constant CursorUp1 (line 86) | CursorUp1 = "\x1b[A"
function CursorDown (line 93) | func CursorDown(n int) string {
function CUD (line 102) | func CUD(n int) string {
constant CUD1 (line 107) | CUD1 = "\x1b[B"
constant CursorDown1 (line 114) | CursorDown1 = "\x1b[B"
function CursorForward (line 121) | func CursorForward(n int) string {
function CUF (line 130) | func CUF(n int) string {
constant CUF1 (line 135) | CUF1 = "\x1b[C"
function CursorRight (line 144) | func CursorRight(n int) string {
constant CursorRight1 (line 153) | CursorRight1 = CUF1
function CursorBackward (line 160) | func CursorBackward(n int) string {
function CUB (line 169) | func CUB(n int) string {
constant CUB1 (line 174) | CUB1 = "\x1b[D"
function CursorLeft (line 183) | func CursorLeft(n int) string {
constant CursorLeft1 (line 192) | CursorLeft1 = CUB1
function CursorNextLine (line 200) | func CursorNextLine(n int) string {
function CNL (line 209) | func CNL(n int) string {
function CursorPreviousLine (line 219) | func CursorPreviousLine(n int) string {
function CPL (line 228) | func CPL(n int) string {
function CursorHorizontalAbsolute (line 240) | func CursorHorizontalAbsolute(col int) string {
function CHA (line 249) | func CHA(col int) string {
function CursorPosition (line 261) | func CursorPosition(col, row int) string {
function CUP (line 277) | func CUP(col, row int) string {
constant CursorHomePosition (line 283) | CursorHomePosition = "\x1b[H"
function SetCursorPosition (line 293) | func SetCursorPosition(col, row int) string {
constant HomeCursorPosition (line 312) | HomeCursorPosition = CursorHomePosition
function MoveCursor (line 322) | func MoveCursor(col, row int) string {
constant CursorOrigin (line 330) | CursorOrigin = "\x1b[1;1H"
constant MoveCursorOrigin (line 336) | MoveCursorOrigin = CursorOrigin
function CursorHorizontalForwardTab (line 346) | func CursorHorizontalForwardTab(n int) string {
function CHT (line 355) | func CHT(n int) string {
function EraseCharacter (line 367) | func EraseCharacter(n int) string {
function ECH (line 376) | func ECH(n int) string {
function CursorBackwardTab (line 388) | func CursorBackwardTab(n int) string {
function CBT (line 397) | func CBT(n int) string {
function VerticalPositionAbsolute (line 409) | func VerticalPositionAbsolute(row int) string {
function VPA (line 418) | func VPA(row int) string {
function VerticalPositionRelative (line 430) | func VerticalPositionRelative(n int) string {
function VPR (line 439) | func VPR(n int) string {
function HorizontalVerticalPosition (line 453) | func HorizontalVerticalPosition(col, row int) string {
function HVP (line 465) | func HVP(col, row int) string {
constant HorizontalVerticalHomePosition (line 472) | HorizontalVerticalHomePosition = "\x1b[f"
constant SaveCurrentCursorPosition (line 484) | SaveCurrentCursorPosition = "\x1b[s"
constant SCOSC (line 485) | SCOSC = SaveCurrentCursorPosition
constant SaveCursorPosition (line 499) | SaveCursorPosition = "\x1b[s"
constant RestoreCurrentCursorPosition (line 511) | RestoreCurrentCursorPosition = "\x1b[u"
constant SCORC (line 512) | SCORC = RestoreCurrentCursorPosition
constant RestoreCursorPosition (line 526) | RestoreCursorPosition = "\x1b[u"
function SetCursorStyle (line 546) | func SetCursorStyle(style int) string {
function DECSCUSR (line 554) | func DECSCUSR(style int) string {
function SetPointerShape (line 576) | func SetPointerShape(shape string) string {
constant ReverseIndex (line 585) | ReverseIndex = "\x1bM"
function HorizontalPositionAbsolute (line 595) | func HorizontalPositionAbsolute(col int) string {
function HPA (line 604) | func HPA(col int) string {
function HorizontalPositionRelative (line 617) | func HorizontalPositionRelative(n int) string {
function HPR (line 626) | func HPR(n int) string {
constant Index (line 633) | Index = "\x1bD"
FILE: vendor/github.com/charmbracelet/x/ansi/cwd.go
function NotifyWorkingDirectory (line 18) | func NotifyWorkingDirectory(host string, paths ...string) string {
FILE: vendor/github.com/charmbracelet/x/ansi/focus.go
constant Focus (line 5) | Focus = "\x1b[I"
constant Blur (line 9) | Blur = "\x1b[O"
FILE: vendor/github.com/charmbracelet/x/ansi/graphics.go
function KittyGraphics (line 22) | func KittyGraphics(payload []byte, opts ...string) string {
function WriteKittyGraphics (line 57) | func WriteKittyGraphics(w io.Writer, m image.Image, o *kitty.Options) er...
function buildChunkOptions (line 176) | func buildChunkOptions(o *kitty.Options, isFirstChunk, isLastChunk bool)...
FILE: vendor/github.com/charmbracelet/x/ansi/hyperlink.go
function SetHyperlink (line 13) | func SetHyperlink(uri string, params ...string) string {
function ResetHyperlink (line 26) | func ResetHyperlink(params ...string) string {
FILE: vendor/github.com/charmbracelet/x/ansi/iterm2.go
function ITerm2 (line 16) | func ITerm2(data any) string {
FILE: vendor/github.com/charmbracelet/x/ansi/keypad.go
constant KeypadApplicationMode (line 13) | KeypadApplicationMode = "\x1b="
constant DECKPAM (line 14) | DECKPAM = KeypadApplicationMode
constant KeypadNumericMode (line 26) | KeypadNumericMode = "\x1b>"
constant DECKPNM (line 27) | DECKPNM = KeypadNumericMode
FILE: vendor/github.com/charmbracelet/x/ansi/kitty.go
constant KittyDisambiguateEscapeCodes (line 8) | KittyDisambiguateEscapeCodes = 1 << iota
constant KittyReportEventTypes (line 9) | KittyReportEventTypes
constant KittyReportAlternateKeys (line 10) | KittyReportAlternateKeys
constant KittyReportAllKeysAsEscapeCodes (line 11) | KittyReportAllKeysAsEscapeCodes
constant KittyReportAssociatedKeys (line 12) | KittyReportAssociatedKeys
constant KittyAllFlags (line 14) | KittyAllFlags = KittyDisambiguateEscapeCodes | KittyReportEventTypes |
constant RequestKittyKeyboard (line 22) | RequestKittyKeyboard = "\x1b[?u"
function KittyKeyboard (line 43) | func KittyKeyboard(flags, mode int) string {
function PushKittyKeyboard (line 62) | func PushKittyKeyboard(flags int) string {
constant DisableKittyKeyboard (line 75) | DisableKittyKeyboard = "\x1b[>u"
function PopKittyKeyboard (line 83) | func PopKittyKeyboard(n int) string {
FILE: vendor/github.com/charmbracelet/x/ansi/kitty/decoder.go
type Decoder (line 16) | type Decoder struct
method Decode (line 33) | func (d *Decoder) Decode(r io.Reader) (image.Image, error) {
method decodeRGBA (line 61) | func (d *Decoder) decodeRGBA(r io.Reader, alpha bool) (image.Image, er...
FILE: vendor/github.com/charmbracelet/x/ansi/kitty/encoder.go
type Encoder (line 15) | type Encoder struct
method Encode (line 24) | func (e *Encoder) Encode(w io.Writer, m image.Image) error {
FILE: vendor/github.com/charmbracelet/x/ansi/kitty/graphics.go
constant MaxChunkSize (line 9) | MaxChunkSize = 1024 * 4
constant Placeholder (line 13) | Placeholder = '\U0010EEEE'
constant RGBA (line 18) | RGBA = 32
constant RGB (line 21) | RGB = 24
constant PNG (line 24) | PNG = 100
constant Zlib (line 29) | Zlib = 'z'
constant Direct (line 35) | Direct = 'd'
constant File (line 38) | File = 'f'
constant TempFile (line 41) | TempFile = 't'
constant SharedMemory (line 46) | SharedMemory = 's'
constant Transmit (line 52) | Transmit = 't'
constant TransmitAndPut (line 54) | TransmitAndPut = 'T'
constant Query (line 56) | Query = 'q'
constant Put (line 58) | Put = 'p'
constant Delete (line 60) | Delete = 'd'
constant Frame (line 62) | Frame = 'f'
constant Animate (line 64) | Animate = 'a'
constant Compose (line 66) | Compose = 'c'
constant DeleteAll (line 72) | DeleteAll = 'a'
constant DeleteID (line 76) | DeleteID = 'i'
constant DeleteNumber (line 80) | DeleteNumber = 'n'
constant DeleteCursor (line 82) | DeleteCursor = 'c'
constant DeleteFrames (line 84) | DeleteFrames = 'f'
constant DeleteCell (line 87) | DeleteCell = 'p'
constant DeleteCellZ (line 90) | DeleteCellZ = 'q'
constant DeleteRange (line 93) | DeleteRange = 'r'
constant DeleteColumn (line 96) | DeleteColumn = 'x'
constant DeleteRow (line 99) | DeleteRow = 'y'
constant DeleteZ (line 102) | DeleteZ = 'z'
function Diacritic (line 107) | func Diacritic(i int) rune {
FILE: vendor/github.com/charmbracelet/x/ansi/kitty/options.go
type Options (line 16) | type Options struct
method Options (line 144) | func (o *Options) Options() (opts []string) {
method String (line 279) | func (o Options) String() string {
method MarshalText (line 284) | func (o Options) MarshalText() ([]byte, error) {
method UnmarshalText (line 289) | func (o *Options) UnmarshalText(text []byte) error {
FILE: vendor/github.com/charmbracelet/x/ansi/method.go
type Method (line 5) | type Method
method StringWidth (line 17) | func (m Method) StringWidth(s string) int {
method Truncate (line 25) | func (m Method) Truncate(s string, length int, tail string) string {
method TruncateLeft (line 33) | func (m Method) TruncateLeft(s string, length int, prefix string) stri...
method Cut (line 41) | func (m Method) Cut(s string, left, right int) string {
method Hardwrap (line 51) | func (m Method) Hardwrap(s string, length int, preserveSpace bool) str...
method Wordwrap (line 63) | func (m Method) Wordwrap(s string, length int, breakpoints string) str...
method Wrap (line 74) | func (m Method) Wrap(s string, length int, breakpoints string) string {
method DecodeSequence (line 122) | func (m Method) DecodeSequence(data []byte, state byte, p *Parser) (se...
method DecodeSequenceInString (line 170) | func (m Method) DecodeSequenceInString(data string, state byte, p *Par...
constant WcWidth (line 9) | WcWidth Method = iota
constant GraphemeWidth (line 10) | GraphemeWidth
FILE: vendor/github.com/charmbracelet/x/ansi/mode.go
type ModeSetting (line 9) | type ModeSetting
method IsNotRecognized (line 21) | func (m ModeSetting) IsNotRecognized() bool {
method IsSet (line 26) | func (m ModeSetting) IsSet() bool {
method IsReset (line 31) | func (m ModeSetting) IsReset() bool {
method IsPermanentlySet (line 36) | func (m ModeSetting) IsPermanentlySet() bool {
method IsPermanentlyReset (line 41) | func (m ModeSetting) IsPermanentlyReset() bool {
constant ModeNotRecognized (line 13) | ModeNotRecognized ModeSetting = iota
constant ModeSet (line 14) | ModeSet
constant ModeReset (line 15) | ModeReset
constant ModePermanentlySet (line 16) | ModePermanentlySet
constant ModePermanentlyReset (line 17) | ModePermanentlyReset
type Mode (line 47) | type Mode interface
function SetMode (line 66) | func SetMode(modes ...Mode) string {
function SM (line 71) | func SM(modes ...Mode) string {
function ResetMode (line 90) | func ResetMode(modes ...Mode) string {
function RM (line 95) | func RM(modes ...Mode) string {
function setMode (line 99) | func setMode(reset bool, modes ...Mode) (s string) {
function RequestMode (line 150) | func RequestMode(m Mode) string {
function DECRQM (line 160) | func DECRQM(m Mode) string {
function ReportMode (line 184) | func ReportMode(mode Mode, value ModeSetting) string {
function DECRPM (line 196) | func DECRPM(mode Mode, value ModeSetting) string {
type ANSIMode (line 201) | type ANSIMode
method Mode (line 204) | func (m ANSIMode) Mode() int {
type DECMode (line 209) | type DECMode
method Mode (line 212) | func (m DECMode) Mode() int {
constant KeyboardActionMode (line 221) | KeyboardActionMode = ANSIMode(2)
constant KAM (line 222) | KAM = KeyboardActionMode
constant SetKeyboardActionMode (line 224) | SetKeyboardActionMode = "\x1b[2h"
constant ResetKeyboardActionMode (line 225) | ResetKeyboardActionMode = "\x1b[2l"
constant RequestKeyboardActionMode (line 226) | RequestKeyboardActionMode = "\x1b[2$p"
constant InsertReplaceMode (line 238) | InsertReplaceMode = ANSIMode(4)
constant IRM (line 239) | IRM = InsertReplaceMode
constant SetInsertReplaceMode (line 241) | SetInsertReplaceMode = "\x1b[4h"
constant ResetInsertReplaceMode (line 242) | ResetInsertReplaceMode = "\x1b[4l"
constant RequestInsertReplaceMode (line 243) | RequestInsertReplaceMode = "\x1b[4$p"
constant SendReceiveMode (line 252) | SendReceiveMode = ANSIMode(12)
constant LocalEchoMode (line 253) | LocalEchoMode = SendReceiveMode
constant SRM (line 254) | SRM = SendReceiveMode
constant SetSendReceiveMode (line 256) | SetSendReceiveMode = "\x1b[12h"
constant ResetSendReceiveMode (line 257) | ResetSendReceiveMode = "\x1b[12l"
constant RequestSendReceiveMode (line 258) | RequestSendReceiveMode = "\x1b[12$p"
constant SetLocalEchoMode (line 260) | SetLocalEchoMode = "\x1b[12h"
constant ResetLocalEchoMode (line 261) | ResetLocalEchoMode = "\x1b[12l"
constant RequestLocalEchoMode (line 262) | RequestLocalEchoMode = "\x1b[12$p"
constant LineFeedNewLineMode (line 277) | LineFeedNewLineMode = ANSIMode(20)
constant LNM (line 278) | LNM = LineFeedNewLineMode
constant SetLineFeedNewLineMode (line 280) | SetLineFeedNewLineMode = "\x1b[20h"
constant ResetLineFeedNewLineMode (line 281) | ResetLineFeedNewLineMode = "\x1b[20l"
constant RequestLineFeedNewLineMode (line 282) | RequestLineFeedNewLineMode = "\x1b[20$p"
constant CursorKeysMode (line 290) | CursorKeysMode = DECMode(1)
constant DECCKM (line 291) | DECCKM = CursorKeysMode
constant SetCursorKeysMode (line 293) | SetCursorKeysMode = "\x1b[?1h"
constant ResetCursorKeysMode (line 294) | ResetCursorKeysMode = "\x1b[?1l"
constant RequestCursorKeysMode (line 295) | RequestCursorKeysMode = "\x1b[?1$p"
constant EnableCursorKeys (line 300) | EnableCursorKeys = "\x1b[?1h"
constant DisableCursorKeys (line 301) | DisableCursorKeys = "\x1b[?1l"
constant OriginMode (line 309) | OriginMode = DECMode(6)
constant DECOM (line 310) | DECOM = OriginMode
constant SetOriginMode (line 312) | SetOriginMode = "\x1b[?6h"
constant ResetOriginMode (line 313) | ResetOriginMode = "\x1b[?6l"
constant RequestOriginMode (line 314) | RequestOriginMode = "\x1b[?6$p"
constant AutoWrapMode (line 322) | AutoWrapMode = DECMode(7)
constant DECAWM (line 323) | DECAWM = AutoWrapMode
constant SetAutoWrapMode (line 325) | SetAutoWrapMode = "\x1b[?7h"
constant ResetAutoWrapMode (line 326) | ResetAutoWrapMode = "\x1b[?7l"
constant RequestAutoWrapMode (line 327) | RequestAutoWrapMode = "\x1b[?7$p"
constant X10MouseMode (line 342) | X10MouseMode = DECMode(9)
constant SetX10MouseMode (line 344) | SetX10MouseMode = "\x1b[?9h"
constant ResetX10MouseMode (line 345) | ResetX10MouseMode = "\x1b[?9l"
constant RequestX10MouseMode (line 346) | RequestX10MouseMode = "\x1b[?9$p"
constant TextCursorEnableMode (line 353) | TextCursorEnableMode = DECMode(25)
constant DECTCEM (line 354) | DECTCEM = TextCursorEnableMode
constant SetTextCursorEnableMode (line 356) | SetTextCursorEnableMode = "\x1b[?25h"
constant ResetTextCursorEnableMode (line 357) | ResetTextCursorEnableMode = "\x1b[?25l"
constant RequestTextCursorEnableMode (line 358) | RequestTextCursorEnableMode = "\x1b[?25$p"
constant ShowCursor (line 363) | ShowCursor = SetTextCursorEnableMode
constant HideCursor (line 364) | HideCursor = ResetTextCursorEnableMode
constant CursorEnableMode (line 373) | CursorEnableMode = DECMode(25)
constant RequestCursorVisibility (line 374) | RequestCursorVisibility = "\x1b[?25$p"
constant NumericKeypadMode (line 384) | NumericKeypadMode = DECMode(66)
constant DECNKM (line 385) | DECNKM = NumericKeypadMode
constant SetNumericKeypadMode (line 387) | SetNumericKeypadMode = "\x1b[?66h"
constant ResetNumericKeypadMode (line 388) | ResetNumericKeypadMode = "\x1b[?66l"
constant RequestNumericKeypadMode (line 389) | RequestNumericKeypadMode = "\x1b[?66$p"
constant BackarrowKeyMode (line 397) | BackarrowKeyMode = DECMode(67)
constant DECBKM (line 398) | DECBKM = BackarrowKeyMode
constant SetBackarrowKeyMode (line 400) | SetBackarrowKeyMode = "\x1b[?67h"
constant ResetBackarrowKeyMode (line 401) | ResetBackarrowKeyMode = "\x1b[?67l"
constant RequestBackarrowKeyMode (line 402) | RequestBackarrowKeyMode = "\x1b[?67$p"
constant LeftRightMarginMode (line 410) | LeftRightMarginMode = DECMode(69)
constant DECLRMM (line 411) | DECLRMM = LeftRightMarginMode
constant SetLeftRightMarginMode (line 413) | SetLeftRightMarginMode = "\x1b[?69h"
constant ResetLeftRightMarginMode (line 414) | ResetLeftRightMarginMode = "\x1b[?69l"
constant RequestLeftRightMarginMode (line 415) | RequestLeftRightMarginMode = "\x1b[?69$p"
constant NormalMouseMode (line 426) | NormalMouseMode = DECMode(1000)
constant SetNormalMouseMode (line 428) | SetNormalMouseMode = "\x1b[?1000h"
constant ResetNormalMouseMode (line 429) | ResetNormalMouseMode = "\x1b[?1000l"
constant RequestNormalMouseMode (line 430) | RequestNormalMouseMode = "\x1b[?1000$p"
constant MouseMode (line 440) | MouseMode = DECMode(1000)
constant EnableMouse (line 442) | EnableMouse = "\x1b[?1000h"
constant DisableMouse (line 443) | DisableMouse = "\x1b[?1000l"
constant RequestMouse (line 444) | RequestMouse = "\x1b[?1000$p"
constant HighlightMouseMode (line 459) | HighlightMouseMode = DECMode(1001)
constant SetHighlightMouseMode (line 461) | SetHighlightMouseMode = "\x1b[?1001h"
constant ResetHighlightMouseMode (line 462) | ResetHighlightMouseMode = "\x1b[?1001l"
constant RequestHighlightMouseMode (line 463) | RequestHighlightMouseMode = "\x1b[?1001$p"
constant MouseHiliteMode (line 473) | MouseHiliteMode = DECMode(1001)
constant EnableMouseHilite (line 475) | EnableMouseHilite = "\x1b[?1001h"
constant DisableMouseHilite (line 476) | DisableMouseHilite = "\x1b[?1001l"
constant RequestMouseHilite (line 477) | RequestMouseHilite = "\x1b[?1001$p"
constant ButtonEventMouseMode (line 485) | ButtonEventMouseMode = DECMode(1002)
constant SetButtonEventMouseMode (line 487) | SetButtonEventMouseMode = "\x1b[?1002h"
constant ResetButtonEventMouseMode (line 488) | ResetButtonEventMouseMode = "\x1b[?1002l"
constant RequestButtonEventMouseMode (line 489) | RequestButtonEventMouseMode = "\x1b[?1002$p"
constant MouseCellMotionMode (line 499) | MouseCellMotionMode = DECMode(1002)
constant EnableMouseCellMotion (line 501) | EnableMouseCellMotion = "\x1b[?1002h"
constant DisableMouseCellMotion (line 502) | DisableMouseCellMotion = "\x1b[?1002l"
constant RequestMouseCellMotion (line 503) | RequestMouseCellMotion = "\x1b[?1002$p"
constant AnyEventMouseMode (line 511) | AnyEventMouseMode = DECMode(1003)
constant SetAnyEventMouseMode (line 513) | SetAnyEventMouseMode = "\x1b[?1003h"
constant ResetAnyEventMouseMode (line 514) | ResetAnyEventMouseMode = "\x1b[?1003l"
constant RequestAnyEventMouseMode (line 515) | RequestAnyEventMouseMode = "\x1b[?1003$p"
constant MouseAllMotionMode (line 525) | MouseAllMotionMode = DECMode(1003)
constant EnableMouseAllMotion (line 527) | EnableMouseAllMotion = "\x1b[?1003h"
constant DisableMouseAllMotion (line 528) | DisableMouseAllMotion = "\x1b[?1003l"
constant RequestMouseAllMotion (line 529) | RequestMouseAllMotion = "\x1b[?1003$p"
constant FocusEventMode (line 542) | FocusEventMode = DECMode(1004)
constant SetFocusEventMode (line 544) | SetFocusEventMode = "\x1b[?1004h"
constant ResetFocusEventMode (line 545) | ResetFocusEventMode = "\x1b[?1004l"
constant RequestFocusEventMode (line 546) | RequestFocusEventMode = "\x1b[?1004$p"
constant ReportFocusMode (line 552) | ReportFocusMode = DECMode(1004)
constant EnableReportFocus (line 554) | EnableReportFocus = "\x1b[?1004h"
constant DisableReportFocus (line 555) | DisableReportFocus = "\x1b[?1004l"
constant RequestReportFocus (line 556) | RequestReportFocus = "\x1b[?1004$p"
constant SgrExtMouseMode (line 570) | SgrExtMouseMode = DECMode(1006)
constant SetSgrExtMouseMode (line 572) | SetSgrExtMouseMode = "\x1b[?1006h"
constant ResetSgrExtMouseMode (line 573) | ResetSgrExtMouseMode = "\x1b[?1006l"
constant RequestSgrExtMouseMode (line 574) | RequestSgrExtMouseMode = "\x1b[?1006$p"
constant MouseSgrExtMode (line 580) | MouseSgrExtMode = DECMode(1006)
constant EnableMouseSgrExt (line 581) | EnableMouseSgrExt = "\x1b[?1006h"
constant DisableMouseSgrExt (line 582) | DisableMouseSgrExt = "\x1b[?1006l"
constant RequestMouseSgrExt (line 583) | RequestMouseSgrExt = "\x1b[?1006$p"
constant Utf8ExtMouseMode (line 591) | Utf8ExtMouseMode = DECMode(1005)
constant SetUtf8ExtMouseMode (line 593) | SetUtf8ExtMouseMode = "\x1b[?1005h"
constant ResetUtf8ExtMouseMode (line 594) | ResetUtf8ExtMouseMode = "\x1b[?1005l"
constant RequestUtf8ExtMouseMode (line 595) | RequestUtf8ExtMouseMode = "\x1b[?1005$p"
constant UrxvtExtMouseMode (line 603) | UrxvtExtMouseMode = DECMode(1015)
constant SetUrxvtExtMouseMode (line 605) | SetUrxvtExtMouseMode = "\x1b[?1015h"
constant ResetUrxvtExtMouseMode (line 606) | ResetUrxvtExtMouseMode = "\x1b[?1015l"
constant RequestUrxvtExtMouseMode (line 607) | RequestUrxvtExtMouseMode = "\x1b[?1015$p"
constant SgrPixelExtMouseMode (line 617) | SgrPixelExtMouseMode = DECMode(1016)
constant SetSgrPixelExtMouseMode (line 619) | SetSgrPixelExtMouseMode = "\x1b[?1016h"
constant ResetSgrPixelExtMouseMode (line 620) | ResetSgrPixelExtMouseMode = "\x1b[?1016l"
constant RequestSgrPixelExtMouseMode (line 621) | RequestSgrPixelExtMouseMode = "\x1b[?1016$p"
constant AltScreenMode (line 630) | AltScreenMode = DECMode(1047)
constant SetAltScreenMode (line 632) | SetAltScreenMode = "\x1b[?1047h"
constant ResetAltScreenMode (line 633) | ResetAltScreenMode = "\x1b[?1047l"
constant RequestAltScreenMode (line 634) | RequestAltScreenMode = "\x1b[?1047$p"
constant SaveCursorMode (line 642) | SaveCursorMode = DECMode(1048)
constant SetSaveCursorMode (line 644) | SetSaveCursorMode = "\x1b[?1048h"
constant ResetSaveCursorMode (line 645) | ResetSaveCursorMode = "\x1b[?1048l"
constant RequestSaveCursorMode (line 646) | RequestSaveCursorMode = "\x1b[?1048$p"
constant AltScreenSaveCursorMode (line 655) | AltScreenSaveCursorMode = DECMode(1049)
constant SetAltScreenSaveCursorMode (line 657) | SetAltScreenSaveCursorMode = "\x1b[?1049h"
constant ResetAltScreenSaveCursorMode (line 658) | ResetAltScreenSaveCursorMode = "\x1b[?1049l"
constant RequestAltScreenSaveCursorMode (line 659) | RequestAltScreenSaveCursorMode = "\x1b[?1049$p"
constant AltScreenBufferMode (line 669) | AltScreenBufferMode = DECMode(1049)
constant SetAltScreenBufferMode (line 671) | SetAltScreenBufferMode = "\x1b[?1049h"
constant ResetAltScreenBufferMode (line 672) | ResetAltScreenBufferMode = "\x1b[?1049l"
constant RequestAltScreenBufferMode (line 673) | RequestAltScreenBufferMode = "\x1b[?1049$p"
constant EnableAltScreenBuffer (line 675) | EnableAltScreenBuffer = "\x1b[?1049h"
constant DisableAltScreenBuffer (line 676) | DisableAltScreenBuffer = "\x1b[?1049l"
constant RequestAltScreenBuffer (line 677) | RequestAltScreenBuffer = "\x1b[?1049$p"
constant BracketedPasteMode (line 686) | BracketedPasteMode = DECMode(2004)
constant SetBracketedPasteMode (line 688) | SetBracketedPasteMode = "\x1b[?2004h"
constant ResetBracketedPasteMode (line 689) | ResetBracketedPasteMode = "\x1b[?2004l"
constant RequestBracketedPasteMode (line 690) | RequestBracketedPasteMode = "\x1b[?2004$p"
constant EnableBracketedPaste (line 696) | EnableBracketedPaste = "\x1b[?2004h"
constant DisableBracketedPaste (line 697) | DisableBracketedPaste = "\x1b[?2004l"
constant RequestBracketedPaste (line 698) | RequestBracketedPaste = "\x1b[?2004$p"
constant SynchronizedOutputMode (line 706) | SynchronizedOutputMode = DECMode(2026)
constant SetSynchronizedOutputMode (line 708) | SetSynchronizedOutputMode = "\x1b[?2026h"
constant ResetSynchronizedOutputMode (line 709) | ResetSynchronizedOutputMode = "\x1b[?2026l"
constant RequestSynchronizedOutputMode (line 710) | RequestSynchronizedOutputMode = "\x1b[?2026$p"
constant SyncdOutputMode (line 716) | SyncdOutputMode = DECMode(2026)
constant EnableSyncdOutput (line 718) | EnableSyncdOutput = "\x1b[?2026h"
constant DisableSyncdOutput (line 719) | DisableSyncdOutput = "\x1b[?2026l"
constant RequestSyncdOutput (line 720) | RequestSyncdOutput = "\x1b[?2026$p"
constant GraphemeClusteringMode (line 730) | GraphemeClusteringMode = DECMode(2027)
constant SetGraphemeClusteringMode (line 732) | SetGraphemeClusteringMode = "\x1b[?2027h"
constant ResetGraphemeClusteringMode (line 733) | ResetGraphemeClusteringMode = "\x1b[?2027l"
constant RequestGraphemeClusteringMode (line 734) | RequestGraphemeClusteringMode = "\x1b[?2027$p"
constant EnableGraphemeClustering (line 740) | EnableGraphemeClustering = "\x1b[?2027h"
constant DisableGraphemeClustering (line 741) | DisableGraphemeClustering = "\x1b[?2027l"
constant RequestGraphemeClustering (line 742) | RequestGraphemeClustering = "\x1b[?2027$p"
constant Win32InputMode (line 750) | Win32InputMode = DECMode(9001)
constant SetWin32InputMode (line 752) | SetWin32InputMode = "\x1b[?9001h"
constant ResetWin32InputMode (line 753) | ResetWin32InputMode = "\x1b[?9001l"
constant RequestWin32InputMode (line 754) | RequestWin32InputMode = "\x1b[?9001$p"
constant EnableWin32Input (line 760) | EnableWin32Input = "\x1b[?9001h"
constant DisableWin32Input (line 761) | DisableWin32Input = "\x1b[?9001l"
constant RequestWin32Input (line 762) | RequestWin32Input = "\x1b[?9001$p"
FILE: vendor/github.com/charmbracelet/x/ansi/modes.go
type Modes (line 5) | type Modes
method Get (line 15) | func (m Modes) Get(mode Mode) ModeSetting {
method Delete (line 21) | func (m Modes) Delete(mode Mode) {
method Set (line 26) | func (m Modes) Set(modes ...Mode) {
method PermanentlySet (line 33) | func (m Modes) PermanentlySet(modes ...Mode) {
method Reset (line 40) | func (m Modes) Reset(modes ...Mode) {
method PermanentlyReset (line 47) | func (m Modes) PermanentlyReset(modes ...Mode) {
method IsSet (line 54) | func (m Modes) IsSet(mode Mode) bool {
method IsPermanentlySet (line 59) | func (m Modes) IsPermanentlySet(mode Mode) bool {
method IsReset (line 64) | func (m Modes) IsReset(mode Mode) bool {
method IsPermanentlyReset (line 69) | func (m Modes) IsPermanentlyReset(mode Mode) bool {
function NewModes (line 9) | func NewModes() Modes {
FILE: vendor/github.com/charmbracelet/x/ansi/mouse.go
type MouseButton (line 8) | type MouseButton
method String (line 69) | func (b MouseButton) String() string {
constant MouseNone (line 28) | MouseNone MouseButton = iota
constant MouseButton1 (line 29) | MouseButton1
constant MouseButton2 (line 30) | MouseButton2
constant MouseButton3 (line 31) | MouseButton3
constant MouseButton4 (line 32) | MouseButton4
constant MouseButton5 (line 33) | MouseButton5
constant MouseButton6 (line 34) | MouseButton6
constant MouseButton7 (line 35) | MouseButton7
constant MouseButton8 (line 36) | MouseButton8
constant MouseButton9 (line 37) | MouseButton9
constant MouseButton10 (line 38) | MouseButton10
constant MouseButton11 (line 39) | MouseButton11
constant MouseLeft (line 41) | MouseLeft = MouseButton1
constant MouseMiddle (line 42) | MouseMiddle = MouseButton2
constant MouseRight (line 43) | MouseRight = MouseButton3
constant MouseWheelUp (line 44) | MouseWheelUp = MouseButton4
constant MouseWheelDown (line 45) | MouseWheelDown = MouseButton5
constant MouseWheelLeft (line 46) | MouseWheelLeft = MouseButton6
constant MouseWheelRight (line 47) | MouseWheelRight = MouseButton7
constant MouseBackward (line 48) | MouseBackward = MouseButton8
constant MouseForward (line 49) | MouseForward = MouseButton9
constant MouseRelease (line 50) | MouseRelease = MouseNone
function EncodeMouseButton (line 97) | func EncodeMouseButton(b MouseButton, motion, shift, alt, ctrl bool) (m ...
constant x10Offset (line 142) | x10Offset = 32
function MouseX10 (line 150) | func MouseX10(b byte, x, y int) string {
function MouseSgr (line 160) | func MouseSgr(b byte, x, y int, release bool) string {
FILE: vendor/github.com/charmbracelet/x/ansi/notification.go
function Notify (line 11) | func Notify(s string) string {
FILE: vendor/github.com/charmbracelet/x/ansi/parser.go
type Parser (line 19) | type Parser struct
method SetParamsSize (line 68) | func (p *Parser) SetParamsSize(size int) {
method SetDataSize (line 76) | func (p *Parser) SetDataSize(size int) {
method Params (line 85) | func (p *Parser) Params() Params {
method Param (line 92) | func (p *Parser) Param(i, def int) (int, bool) {
method Command (line 101) | func (p *Parser) Command() int {
method Rune (line 106) | func (p *Parser) Rune() rune {
method Control (line 116) | func (p *Parser) Control() byte {
method Data (line 121) | func (p *Parser) Data() []byte {
method Reset (line 126) | func (p *Parser) Reset() {
method clear (line 132) | func (p *Parser) clear() {
method State (line 141) | func (p *Parser) State() parser.State {
method StateName (line 146) | func (p *Parser) StateName() string {
method Parse (line 152) | func (p *Parser) Parse(b []byte) {
method Advance (line 160) | func (p *Parser) Advance(b byte) parser.Action {
method collectRune (line 170) | func (p *Parser) collectRune(b byte) {
method advanceUtf8 (line 181) | func (p *Parser) advanceUtf8(b byte) parser.Action {
method advance (line 206) | func (p *Parser) advance(b byte) parser.Action {
method parseStringCmd (line 242) | func (p *Parser) parseStringCmd() {
method performAction (line 261) | func (p *Parser) performAction(action parser.Action, state parser.Stat...
function NewParser (line 59) | func NewParser() *Parser {
function utf8ByteLen (line 406) | func utf8ByteLen(b byte) int {
FILE: vendor/github.com/charmbracelet/x/ansi/parser/const.go
constant NoneAction (line 8) | NoneAction Action = iota
constant ClearAction (line 9) | ClearAction
constant CollectAction (line 10) | CollectAction
constant PrefixAction (line 11) | PrefixAction
constant DispatchAction (line 12) | DispatchAction
constant ExecuteAction (line 13) | ExecuteAction
constant StartAction (line 14) | StartAction
constant PutAction (line 15) | PutAction
constant ParamAction (line 16) | ParamAction
constant PrintAction (line 17) | PrintAction
constant IgnoreAction (line 19) | IgnoreAction = NoneAction
constant GroundState (line 41) | GroundState State = iota
constant CsiEntryState (line 42) | CsiEntryState
constant CsiIntermediateState (line 43) | CsiIntermediateState
constant CsiParamState (line 44) | CsiParamState
constant DcsEntryState (line 45) | DcsEntryState
constant DcsIntermediateState (line 46) | DcsIntermediateState
constant DcsParamState (line 47) | DcsParamState
constant DcsStringState (line 48) | DcsStringState
constant EscapeState (line 49) | EscapeState
constant EscapeIntermediateState (line 50) | EscapeIntermediateState
constant OscStringState (line 51) | OscStringState
constant SosStringState (line 52) | SosStringState
constant PmStringState (line 53) | PmStringState
constant ApcStringState (line 54) | ApcStringState
constant Utf8State (line 58) | Utf8State
FILE: vendor/github.com/charmbracelet/x/ansi/parser/seq.go
constant PrefixShift (line 7) | PrefixShift = 8
constant IntermedShift (line 8) | IntermedShift = 16
constant FinalMask (line 9) | FinalMask = 0xff
constant HasMoreFlag (line 10) | HasMoreFlag = math.MinInt32
constant ParamMask (line 11) | ParamMask = ^HasMoreFlag
constant MissingParam (line 12) | MissingParam = ParamMask
constant MissingCommand (line 13) | MissingCommand = MissingParam
constant MaxParam (line 14) | MaxParam = math.MaxUint16
constant MaxParamsSize (line 19) | MaxParamsSize = 32
constant DefaultParamValue (line 22) | DefaultParamValue = 0
function Prefix (line 29) | func Prefix(cmd int) int {
function Intermediate (line 38) | func Intermediate(cmd int) int {
function Command (line 43) | func Command(cmd int) int {
function Param (line 49) | func Param(params []int, i int) int {
function HasMore (line 63) | func HasMore(params []int, i int) bool {
function Subparams (line 73) | func Subparams(params []int, i int) []int {
function Len (line 117) | func Len(params []int) int {
function Range (line 130) | func Range(params []int, fn func(i int, param int, hasMore bool) bool) {
FILE: vendor/github.com/charmbracelet/x/ansi/parser/transition_table.go
constant TransitionActionShift (line 8) | TransitionActionShift = 4
constant TransitionStateMask (line 9) | TransitionStateMask = 15
constant IndexStateShift (line 10) | IndexStateShift = 8
constant DefaultTableSize (line 13) | DefaultTableSize = 4096
type TransitionTable (line 21) | type TransitionTable
method SetDefault (line 32) | func (t TransitionTable) SetDefault(action Action, state State) {
method AddOne (line 39) | func (t TransitionTable) AddOne(code byte, state State, action Action,...
method AddMany (line 46) | func (t TransitionTable) AddMany(codes []byte, state State, action Act...
method AddRange (line 53) | func (t TransitionTable) AddRange(start, end byte, state State, action...
method Transition (line 60) | func (t TransitionTable) Transition(state State, code byte) (State, Ac...
function NewTransitionTable (line 24) | func NewTransitionTable(size int) TransitionTable {
function r (line 67) | func r(start, end byte) []byte {
function GenerateTransitionTable (line 87) | func GenerateTransitionTable() TransitionTable {
FILE: vendor/github.com/charmbracelet/x/ansi/parser_decode.go
constant NormalState (line 17) | NormalState State = iota
constant PrefixState (line 18) | PrefixState
constant ParamsState (line 19) | ParamsState
constant IntermedState (line 20) | IntermedState
constant EscapeState (line 21) | EscapeState
constant StringState (line 22) | StringState
function DecodeSequence (line 71) | func DecodeSequence[T string | []byte](b T, state byte, p *Parser) (seq ...
function DecodeSequenceWc (line 121) | func DecodeSequenceWc[T string | []byte](b T, state byte, p *Parser) (se...
function decodeSequence (line 125) | func decodeSequence[T string | []byte](m Method, b T, state State, p *Pa...
function parseOscCmd (line 358) | func parseOscCmd(p *Parser) {
function Equal (line 376) | func Equal[T string | []byte](a, b T) bool {
function HasPrefix (line 381) | func HasPrefix[T string | []byte](b, prefix T) bool {
function HasSuffix (line 386) | func HasSuffix[T string | []byte](b, suffix T) bool {
function HasCsiPrefix (line 391) | func HasCsiPrefix[T string | []byte](b T) bool {
function HasOscPrefix (line 397) | func HasOscPrefix[T string | []byte](b T) bool {
function HasApcPrefix (line 403) | func HasApcPrefix[T string | []byte](b T) bool {
function HasDcsPrefix (line 409) | func HasDcsPrefix[T string | []byte](b T) bool {
function HasSosPrefix (line 415) | func HasSosPrefix[T string | []byte](b T) bool {
function HasPmPrefix (line 421) | func HasPmPrefix[T string | []byte](b T) bool {
function HasStPrefix (line 427) | func HasStPrefix[T string | []byte](b T) bool {
function HasEscPrefix (line 433) | func HasEscPrefix[T string | []byte](b T) bool {
function FirstGraphemeCluster (line 440) | func FirstGraphemeCluster[T string | []byte](b T, state int) (T, T, int,...
type Cmd (line 455) | type Cmd
method Prefix (line 461) | func (c Cmd) Prefix() byte {
method Intermediate (line 470) | func (c Cmd) Intermediate() byte {
method Final (line 475) | func (c Cmd) Final() byte {
function Command (line 489) | func Command(prefix, inter, final byte) (c int) {
type Param (line 499) | type Param
method Param (line 503) | func (s Param) Param(def int) int {
method HasMore (line 512) | func (s Param) HasMore() bool {
function Parameter (line 518) | func Parameter(p int, hasMore bool) (s int) {
FILE: vendor/github.com/charmbracelet/x/ansi/parser_handler.go
type Params (line 6) | type Params
method Param (line 12) | func (p Params) Param(i, def int) (int, bool, bool) {
method ForEach (line 23) | func (p Params) ForEach(def int, f func(i, param int, hasMore bool)) {
function ToParams (line 30) | func ToParams(params []int) Params {
type Handler (line 36) | type Handler struct
method SetHandler (line 58) | func (p *Parser) SetHandler(h Handler) {
FILE: vendor/github.com/charmbracelet/x/ansi/parser_sync.go
function GetParser (line 19) | func GetParser() *Parser {
function PutParser (line 25) | func PutParser(p *Parser) {
FILE: vendor/github.com/charmbracelet/x/ansi/passthrough.go
function ScreenPassthrough (line 19) | func ScreenPassthrough(seq string, limit int) string {
function TmuxPassthrough (line 52) | func TmuxPassthrough(seq string) string {
FILE: vendor/github.com/charmbracelet/x/ansi/paste.go
constant BracketedPasteStart (line 4) | BracketedPasteStart = "\x1b[200~"
constant BracketedPasteEnd (line 7) | BracketedPasteEnd = "\x1b[201~"
FILE: vendor/github.com/charmbracelet/x/ansi/reset.go
constant ResetInitialState (line 9) | ResetInitialState = "\x1bc"
constant RIS (line 10) | RIS = ResetInitialState
FILE: vendor/github.com/charmbracelet/x/ansi/screen.go
function EraseDisplay (line 22) | func EraseDisplay(n int) string {
function ED (line 31) | func ED(n int) string {
constant EraseScreenBelow (line 38) | EraseScreenBelow = "\x1b[J"
constant EraseScreenAbove (line 39) | EraseScreenAbove = "\x1b[1J"
constant EraseEntireScreen (line 40) | EraseEntireScreen = "\x1b[2J"
constant EraseEntireDisplay (line 41) | EraseEntireDisplay = "\x1b[3J"
function EraseLine (line 55) | func EraseLine(n int) string {
function EL (line 64) | func EL(n int) string {
constant EraseLineRight (line 71) | EraseLineRight = "\x1b[K"
constant EraseLineLeft (line 72) | EraseLineLeft = "\x1b[1K"
constant EraseEntireLine (line 73) | EraseEntireLine = "\x1b[2K"
function ScrollUp (line 82) | func ScrollUp(n int) string {
function PanDown (line 91) | func PanDown(n int) string {
function SU (line 96) | func SU(n int) string {
function ScrollDown (line 106) | func ScrollDown(n int) string {
function PanUp (line 115) | func PanUp(n int) string {
function SD (line 120) | func SD(n int) string {
function InsertLine (line 130) | func InsertLine(n int) string {
function IL (line 139) | func IL(n int) string {
function DeleteLine (line 149) | func DeleteLine(n int) string {
function DL (line 158) | func DL(n int) string {
function SetTopBottomMargins (line 170) | func SetTopBottomMargins(top, bot int) string {
function DECSTBM (line 182) | func DECSTBM(top, bot int) string {
function SetLeftRightMargins (line 194) | func SetLeftRightMargins(left, right int) string {
function DECSLRM (line 206) | func DECSLRM(left, right int) string {
function SetScrollingRegion (line 218) | func SetScrollingRegion(t, b int) string {
function InsertCharacter (line 237) | func InsertCharacter(n int) string {
function ICH (line 246) | func ICH(n int) string {
function DeleteCharacter (line 259) | func DeleteCharacter(n int) string {
function DCH (line 268) | func DCH(n int) string {
constant SetTabEvery8Columns (line 278) | SetTabEvery8Columns = "\x1b[?5W"
constant DECST8C (line 279) | DECST8C = SetTabEvery8Columns
constant HorizontalTabSet (line 290) | HorizontalTabSet = "\x1bH"
function TabClear (line 303) | func TabClear(n int) string {
function TBC (line 312) | func TBC(n int) string {
function RequestPresentationStateReport (line 330) | func RequestPresentationStateReport(n int) string {
function DECRQPSR (line 339) | func DECRQPSR(n int) string {
function TabStopReport (line 353) | func TabStopReport(stops ...int) string {
function DECTABSR (line 362) | func DECTABSR(stops ...int) string {
function CursorInformationReport (line 378) | func CursorInformationReport(values ...int) string {
function DECCIR (line 387) | func DECCIR(values ...int) string {
function RepeatPreviousCharacter (line 399) | func RepeatPreviousCharacter(n int) string {
function REP (line 408) | func REP(n int) string {
FILE: vendor/github.com/charmbracelet/x/ansi/sgr.go
function SelectGraphicRendition (line 12) | func SelectGraphicRendition(ps ...Attr) string {
function SGR (line 34) | func SGR(ps ...Attr) string {
FILE: vendor/github.com/charmbracelet/x/ansi/status.go
type StatusReport (line 9) | type StatusReport interface
type ANSIStatusReport (line 15) | type ANSIStatusReport
method StatusReport (line 18) | func (s ANSIStatusReport) StatusReport() int {
type DECStatusReport (line 23) | type DECStatusReport
method StatusReport (line 26) | func (s DECStatusReport) StatusReport() int {
function DeviceStatusReport (line 41) | func DeviceStatusReport(statues ...StatusReport) string {
function DSR (line 59) | func DSR(status StatusReport) string {
constant RequestCursorPositionReport (line 75) | RequestCursorPositionReport = "\x1b[6n"
constant RequestExtendedCursorPositionReport (line 90) | RequestExtendedCursorPositionReport = "\x1b[?6n"
function CursorPositionReport (line 100) | func CursorPositionReport(line, column int) string {
function CPR (line 111) | func CPR(line, column int) string {
function ExtendedCursorPositionReport (line 128) | func ExtendedCursorPositionReport(line, column, page int) string {
function DECXCPR (line 142) | func DECXCPR(line, column, page int) string {
FILE: vendor/github.com/charmbracelet/x/ansi/style.go
constant ResetStyle (line 12) | ResetStyle = "\x1b[m"
type Style (line 18) | type Style
method String (line 22) | func (s Style) String() string {
method Styled (line 30) | func (s Style) Styled(str string) string {
method Reset (line 38) | func (s Style) Reset() Style {
method Bold (line 43) | func (s Style) Bold() Style {
method Faint (line 48) | func (s Style) Faint() Style {
method Italic (line 53) | func (s Style) Italic() Style {
method Underline (line 58) | func (s Style) Underline() Style {
method UnderlineStyle (line 63) | func (s Style) UnderlineStyle(u UnderlineStyle) Style {
method DoubleUnderline (line 83) | func (s Style) DoubleUnderline() Style {
method CurlyUnderline (line 89) | func (s Style) CurlyUnderline() Style {
method DottedUnderline (line 95) | func (s Style) DottedUnderline() Style {
method DashedUnderline (line 101) | func (s Style) DashedUnderline() Style {
method SlowBlink (line 106) | func (s Style) SlowBlink() Style {
method RapidBlink (line 111) | func (s Style) RapidBlink() Style {
method Reverse (line 116) | func (s Style) Reverse() Style {
method Conceal (line 121) | func (s Style) Conceal() Style {
method Strikethrough (line 126) | func (s Style) Strikethrough() Style {
method NoBold (line 131) | func (s Style) NoBold() Style {
method NormalIntensity (line 136) | func (s Style) NormalIntensity() Style {
method NoItalic (line 141) | func (s Style) NoItalic() Style {
method NoUnderline (line 146) | func (s Style) NoUnderline() Style {
method NoBlink (line 151) | func (s Style) NoBlink() Style {
method NoReverse (line 156) | func (s Style) NoReverse() Style {
method NoConceal (line 161) | func (s Style) NoConceal() Style {
method NoStrikethrough (line 166) | func (s Style) NoStrikethrough() Style {
method DefaultForegroundColor (line 171) | func (s Style) DefaultForegroundColor() Style {
method DefaultBackgroundColor (line 176) | func (s Style) DefaultBackgroundColor() Style {
method DefaultUnderlineColor (line 181) | func (s Style) DefaultUnderlineColor() Style {
method ForegroundColor (line 186) | func (s Style) ForegroundColor(c Color) Style {
method BackgroundColor (line 191) | func (s Style) BackgroundColor(c Color) Style {
method UnderlineColor (line 196) | func (s Style) UnderlineColor(c Color) Style {
constant doubleUnderlineStyle (line 205) | doubleUnderlineStyle = "4:2"
constant curlyUnderlineStyle (line 206) | curlyUnderlineStyle = "4:3"
constant dottedUnderlineStyle (line 207) | dottedUnderlineStyle = "4:4"
constant dashedUnderlineStyle (line 208) | dashedUnderlineStyle = "4:5"
constant NoUnderlineStyle (line 213) | NoUnderlineStyle UnderlineStyle = iota
constant SingleUnderlineStyle (line 215) | SingleUnderlineStyle
constant DoubleUnderlineStyle (line 217) | DoubleUnderlineStyle
constant CurlyUnderlineStyle (line 219) | CurlyUnderlineStyle
constant DottedUnderlineStyle (line 221) | DottedUnderlineStyle
constant DashedUnderlineStyle (line 223) | DashedUnderlineStyle
constant ResetAttr (line 229) | ResetAttr Attr = 0
constant BoldAttr (line 230) | BoldAttr Attr = 1
constant FaintAttr (line 231) | FaintAttr Attr = 2
constant ItalicAttr (line 232) | ItalicAttr Attr = 3
constant UnderlineAttr (line 233) | UnderlineAttr Attr = 4
constant SlowBlinkAttr (line 234) | SlowBlinkAttr Attr = 5
constant RapidBlinkAttr (line 235) | RapidBlinkAttr Attr = 6
constant ReverseAttr (line 236) | ReverseAttr Attr = 7
constant ConcealAttr (line 237) | ConcealAttr Attr = 8
constant StrikethroughAttr (line 238) | StrikethroughAttr Attr = 9
constant NoBoldAttr (line 239) | NoBoldAttr Attr = 21
constant NormalIntensityAttr (line 240) | NormalIntensityAttr Attr = 22
constant NoItalicAttr (line 241) | NoItalicAttr Attr = 23
constant NoUnderlineAttr (line 242) | NoUnderlineAttr Attr = 24
constant NoBlinkAttr (line 243) | NoBlinkAttr Attr = 25
constant NoReverseAttr (line 244) | NoReverseAttr Attr = 27
constant NoConcealAttr (line 245) | NoConcealAttr Attr = 28
constant NoStrikethroughAttr (line 246) | NoStrikethroughAttr Attr = 29
constant BlackForegroundColorAttr (line 247) | BlackForegroundColorAttr Attr = 30
constant RedForegroundColorAttr (line 248) | RedForegroundColorAttr Attr = 31
constant GreenForegroundColorAttr (line 249) | GreenForegroundColorAttr Attr = 32
constant YellowForegroundColorAttr (line 250) | YellowForegroundColorAttr Attr = 33
constant BlueForegroundColorAttr (line 251) | BlueForegroundColorAttr Attr = 34
constant MagentaForegroundColorAttr (line 252) | MagentaForegroundColorAttr Attr = 35
constant CyanForegroundColorAttr (line 253) | CyanForegroundColorAttr Attr = 36
constant WhiteForegroundColorAttr (line 254) | WhiteForegroundColorAttr Attr = 37
constant ExtendedForegroundColorAttr (line 255) | ExtendedForegroundColorAttr Attr = 38
constant DefaultForegroundColorAttr (line 256) | DefaultForegroundColorAttr Attr = 39
constant BlackBackgroundColorAttr (line 257) | BlackBackgroundColorAttr Attr = 40
constant RedBackgroundColorAttr (line 258) | RedBackgroundColorAttr Attr = 41
constant GreenBackgroundColorAttr (line 259) | GreenBackgroundColorAttr Attr = 42
constant YellowBackgroundColorAttr (line 260) | YellowBackgroundColorAttr Attr = 43
constant BlueBackgroundColorAttr (line 261) | BlueBackgroundColorAttr Attr = 44
constant MagentaBackgroundColorAttr (line 262) | MagentaBackgroundColorAttr Attr = 45
constant CyanBackgroundColorAttr (line 263) | CyanBackgroundColorAttr Attr = 46
constant WhiteBackgroundColorAttr (line 264) | WhiteBackgroundColorAttr Attr = 47
constant ExtendedBackgroundColorAttr (line 265) | ExtendedBackgroundColorAttr Attr = 48
constant DefaultBackgroundColorAttr (line 266) | DefaultBackgroundColorAttr Attr = 49
constant ExtendedUnderlineColorAttr (line 267) | ExtendedUnderlineColorAttr Attr = 58
constant DefaultUnderlineColorAttr (line 268) | DefaultUnderlineColorAttr Attr = 59
constant BrightBlackForegroundColorAttr (line 269) | BrightBlackForegroundColorAttr Attr = 90
constant BrightRedForegroundColorAttr (line 270) | BrightRedForegroundColorAttr Attr = 91
constant BrightGreenForegroundColorAttr (line 271) | BrightGreenForegroundColorAttr Attr = 92
constant BrightYellowForegroundColorAttr (line 272) | BrightYellowForegroundColorAttr Attr = 93
constant BrightBlueForegroundColorAttr (line 273) | BrightBlueForegroundColorAttr Attr = 94
constant BrightMagentaForegroundColorAttr (line 274) | BrightMagentaForegroundColorAttr Attr = 95
constant BrightCyanForegroundColorAttr (line 275) | BrightCyanForegroundColorAttr Attr = 96
constant BrightWhiteForegroundColorAttr (line 276) | BrightWhiteForegroundColorAttr Attr = 97
constant BrightBlackBackgroundColorAttr (line 277) | BrightBlackBackgroundColorAttr Attr = 100
constant BrightRedBackgroundColorAttr (line 278) | BrightRedBackgroundColorAttr Attr = 101
constant BrightGreenBackgroundColorAttr (line 279) | BrightGreenBackgroundColorAttr Attr = 102
constant BrightYellowBackgroundColorAttr (line 280) | BrightYellowBackgroundColorAttr Attr = 103
constant BrightBlueBackgroundColorAttr (line 281) | BrightBlueBackgroundColorAttr Attr = 104
constant BrightMagentaBackgroundColorAttr (line 282) | BrightMagentaBackgroundColorAttr Attr = 105
constant BrightCyanBackgroundColorAttr (line 283) | BrightCyanBackgroundColorAttr Attr = 106
constant BrightWhiteBackgroundColorAttr (line 284) | BrightWhiteBackgroundColorAttr Attr = 107
constant RGBColorIntroducerAttr (line 286) | RGBColorIntroducerAttr Attr = 2
constant ExtendedColorIntroducerAttr (line 287) | ExtendedColorIntroducerAttr Attr = 5
constant resetAttr (line 291) | resetAttr = "0"
constant boldAttr (line 292) | boldAttr = "1"
constant faintAttr (line 293) | faintAttr = "2"
constant italicAttr (line 294) | italicAttr = "3"
constant underlineAttr (line 295) | underlineAttr = "4"
constant slowBlinkAttr (line 296) | slowBlinkAttr = "5"
constant rapidBlinkAttr (line 297) | rapidBlinkAttr = "6"
constant reverseAttr (line 298) | reverseAttr = "7"
constant concealAttr (line 299) | concealAttr = "8"
constant strikethroughAttr (line 300) | strikethroughAttr = "9"
constant noBoldAttr (line 301) | noBoldAttr = "21"
constant normalIntensityAttr (line 302) | normalIntensityAttr = "22"
constant noItalicAttr (line 303) | noItalicAttr = "23"
constant noUnderlineAttr (line 304) | noUnderlineAttr = "24"
constant noBlinkAttr (line 305) | noBlinkAttr = "25"
constant noReverseAttr (line 306) | noReverseAttr = "27"
constant noConcealAttr (line 307) | noConcealAttr = "28"
constant noStrikethroughAttr (line 308) | noStrikethroughAttr = "29"
constant blackForegroundColorAttr (line 309) | blackForegroundColorAttr = "30"
constant redForegroundColorAttr (line 310) | redForegroundColorAttr = "31"
constant greenForegroundColorAttr (line 311) | greenForegroundColorAttr = "32"
constant yellowForegroundColorAttr (line 312) | yellowForegroundColorAttr = "33"
constant blueForegroundColorAttr (line 313) | blueForegroundColorAttr = "34"
constant magentaForegroundColorAttr (line 314) | magentaForegroundColorAttr = "35"
constant cyanForegroundColorAttr (line 315) | cyanForegroundColorAttr = "36"
constant whiteForegroundColorAttr (line 316) | whiteForegroundColorAttr = "37"
constant extendedForegroundColorAttr (line 317) | extendedForegroundColorAttr = "38"
constant defaultForegroundColorAttr (line 318) | defaultForegroundColorAttr = "39"
constant blackBackgroundColorAttr (line 319) | blackBackgroundColorAttr = "40"
constant redBackgroundColorAttr (line 320) | redBackgroundColorAttr = "41"
constant greenBackgroundColorAttr (line 321) | greenBackgroundColorAttr = "42"
constant yellowBackgroundColorAttr (line 322) | yellowBackgroundColorAttr = "43"
constant blueBackgroundColorAttr (line 323) | blueBackgroundColorAttr = "44"
constant magentaBackgroundColorAttr (line 324) | magentaBackgroundColorAttr = "45"
constant cyanBackgroundColorAttr (line 325) | cyanBackgroundColorAttr = "46"
constant whiteBackgroundColorAttr (line 326) | whiteBackgroundColorAttr = "47"
constant extendedBackgroundColorAttr (line 327) | extendedBackgroundColorAttr = "48"
constant defaultBackgroundColorAttr (line 328) | defaultBackgroundColorAttr = "49"
constant extendedUnderlineColorAttr (line 329) | extendedUnderlineColorAttr = "58"
constant defaultUnderlineColorAttr (line 330) | defaultUnderlineColorAttr = "59"
constant brightBlackForegroundColorAttr (line 331) | brightBlackForegroundColorAttr = "90"
constant brightRedForegroundColorAttr (line 332) | brightRedForegroundColorAttr = "91"
constant brightGreenForegroundColorAttr (line 333) | brightGreenForegroundColorAttr = "92"
constant brightYellowForegroundColorAttr (line 334) | brightYellowForegroundColorAttr = "93"
constant brightBlueForegroundColorAttr (line 335) | brightBlueForegroundColorAttr = "94"
constant brightMagentaForegroundColorAttr (line 336) | brightMagentaForegroundColorAttr = "95"
constant brightCyanForegroundColorAttr (line 337) | brightCyanForegroundColorAttr = "96"
constant brightWhiteForegroundColorAttr (line 338) | brightWhiteForegroundColorAttr = "97"
constant brightBlackBackgroundColorAttr (line 339) | brightBlackBackgroundColorAttr = "100"
constant brightRedBackgroundColorAttr (line 340) | brightRedBackgroundColorAttr = "101"
constant brightGreenBackgroundColorAttr (line 341) | brightGreenBackgroundColorAttr = "102"
constant brightYellowBackgroundColorAttr (line 342) | brightYellowBackgroundColorAttr = "103"
constant brightBlueBackgroundColorAttr (line 343) | brightBlueBackgroundColorAttr = "104"
constant brightMagentaBackgroundColorAttr (line 344) | brightMagentaBackgroundColorAttr = "105"
constant brightCyanBackgroundColorAttr (line 345) | brightCyanBackgroundColorAttr = "106"
constant brightWhiteBackgroundColorAttr (line 346) | brightWhiteBackgroundColorAttr = "107"
function foregroundColorString (line 352) | func foregroundColorString(c Color) string {
function backgroundColorString (line 410) | func backgroundColorString(c Color) string {
function underlineColorString (line 468) | func underlineColorString(c Color) string {
function ReadStyleColor (line 516) | func ReadStyleColor(params Params, co *color.Color) (n int) {
FILE: vendor/github.com/charmbracelet/x/ansi/termcap.go
function XTGETTCAP (line 17) | func XTGETTCAP(caps ...string) string {
function RequestTermcap (line 34) | func RequestTermcap(caps ...string) string {
function RequestTerminfo (line 39) | func RequestTerminfo(caps ...string) string {
FILE: vendor/github.com/charmbracelet/x/ansi/title.go
function SetIconNameWindowTitle (line 10) | func SetIconNameWindowTitle(s string) string {
function SetIconName (line 20) | func SetIconName(s string) string {
function SetWindowTitle (line 30) | func SetWindowTitle(s string) string {
FILE: vendor/github.com/charmbracelet/x/ansi/truncate.go
function Cut (line 16) | func Cut(s string, left, right int) string {
function CutWc (line 25) | func CutWc(s string, left, right int) string {
function cut (line 29) | func cut(m Method, s string, left, right int) string {
function Truncate (line 52) | func Truncate(s string, length int, tail string) string {
function TruncateWc (line 61) | func TruncateWc(s string, length int, tail string) string {
function truncate (line 65) | func truncate(m Method, s string, length int, tail string) string {
function TruncateLeft (line 169) | func TruncateLeft(s string, n int, prefix string) string {
function TruncateLeftWc (line 178) | func TruncateLeftWc(s string, n int, prefix string) string {
function truncateLeft (line 182) | func truncateLeft(m Method, s string, n int, prefix string) string {
function ByteToGraphemeRange (line 262) | func ByteToGraphemeRange(str string, byteStart, byteStop int) (charStart...
FILE: vendor/github.com/charmbracelet/x/ansi/util.go
function colorToHexString (line 13) | func colorToHexString(c color.Color) string {
function rgbToHex (line 31) | func rgbToHex(r, g, b uint32) uint32 {
type shiftable (line 35) | type shiftable interface
function shift (line 39) | func shift[T shiftable](x T) T {
function XParseColor (line 58) | func XParseColor(s string) color.Color {
type ordered (line 94) | type ordered interface
function max (line 101) | func max[T ordered](a, b T) T { //nolint:predeclared
FILE: vendor/github.com/charmbracelet/x/ansi/width.go
function Strip (line 12) | func Strip(s string) string {
function StringWidth (line 67) | func StringWidth(s string) int {
function StringWidthWc (line 76) | func StringWidthWc(s string) int {
function stringWidth (line 80) | func stringWidth(m Method, s string) int {
FILE: vendor/github.com/charmbracelet/x/ansi/winop.go
constant ResizeWindowWinOp (line 11) | ResizeWindowWinOp = 4
constant RequestWindowSizeWinOp (line 16) | RequestWindowSizeWinOp = 14
constant RequestCellSizeWinOp (line 21) | RequestCellSizeWinOp = 16
function WindowOp (line 30) | func WindowOp(p int, ps ...int) string {
function XTWINOPS (line 51) | func XTWINOPS(p int, ps ...int) string {
FILE: vendor/github.com/charmbracelet/x/ansi/wrap.go
constant nbsp (line 14) | nbsp = 0xA0
function Hardwrap (line 22) | func Hardwrap(s string, limit int, preserveSpace bool) string {
function HardwrapWc (line 32) | func HardwrapWc(s string, limit int, preserveSpace bool) string {
function hardwrap (line 36) | func hardwrap(m Method, s string, limit int, preserveSpace bool) string {
function Wordwrap (line 132) | func Wordwrap(s string, limit int, breakpoints string) string {
function WordwrapWc (line 146) | func WordwrapWc(s string, limit int, breakpoints string) string {
function wordwrap (line 150) | func wordwrap(m Method, s string, limit int, breakpoints string) string {
function Wrap (line 283) | func Wrap(s string, limit int, breakpoints string) string {
function WrapWc (line 296) | func WrapWc(s string, limit int, breakpoints string) string {
function wrap (line 300) | func wrap(m Method, s string, limit int, breakpoints string) string {
function runeContainsAny (line 460) | func runeContainsAny(r rune, s string) bool {
FILE: vendor/github.com/charmbracelet/x/ansi/xterm.go
function KeyModifierOptions (line 15) | func KeyModifierOptions(p int, vs ...int) string {
function XTMODKEYS (line 35) | func XTMODKEYS(p int, vs ...int) string {
function SetKeyModifierOptions (line 41) | func SetKeyModifierOptions(pp int, pv int) string {
function ResetKeyModifierOptions (line 47) | func ResetKeyModifierOptions(pp int) string {
function QueryKeyModifierOptions (line 58) | func QueryKeyModifierOptions(pp int) string {
function XTQMODKEYS (line 67) | func XTQMODKEYS(pp int) string {
constant SetModifyOtherKeys1 (line 77) | SetModifyOtherKeys1 = "\x1b[>4;1m"
constant SetModifyOtherKeys2 (line 78) | SetModifyOtherKeys2 = "\x1b[>4;2m"
constant ResetModifyOtherKeys (line 79) | ResetModifyOtherKeys = "\x1b[>4m"
constant QueryModifyOtherKeys (line 80) | QueryModifyOtherKeys = "\x1b[?4m"
function ModifyOtherKeys (line 96) | func ModifyOtherKeys(mode int) string {
constant DisableModifyOtherKeys (line 108) | DisableModifyOtherKeys = "\x1b[>4;0m"
constant EnableModifyOtherKeys1 (line 118) | EnableModifyOtherKeys1 = "\x1b[>4;1m"
constant EnableModifyOtherKeys2 (line 128) | EnableModifyOtherKeys2 = "\x1b[>4;2m"
constant RequestModifyOtherKeys (line 138) | RequestModifyOtherKeys = "\x1b[?4m"
FILE: vendor/github.com/charmbracelet/x/term/term.go
type State (line 4) | type State struct
function IsTerminal (line 9) | func IsTerminal(fd uintptr) bool {
function MakeRaw (line 16) | func MakeRaw(fd uintptr) (*State, error) {
function GetState (line 22) | func GetState(fd uintptr) (*State, error) {
function SetState (line 27) | func SetState(fd uintptr, state *State) error {
function Restore (line 33) | func Restore(fd uintptr, oldState *State) error {
function GetSize (line 40) | func GetSize(fd uintptr) (width, height int, err error) {
function ReadPassword (line 47) | func ReadPassword(fd uintptr) ([]byte, error) {
FILE: vendor/github.com/charmbracelet/x/term/term_other.go
type state (line 11) | type state struct
function isTerminal (line 13) | func isTerminal(fd uintptr) bool {
function makeRaw (line 17) | func makeRaw(fd uintptr) (*State, error) {
function getState (line 21) | func getState(fd uintptr) (*State, error) {
function restore (line 25) | func restore(fd uintptr, state *State) error {
function getSize (line 29) | func getSize(fd uintptr) (width, height int, err error) {
function setState (line 33) | func setState(fd uintptr, state *State) error {
function readPassword (line 37) | func readPassword(fd uintptr) ([]byte, error) {
FILE: vendor/github.com/charmbracelet/x/term/term_unix.go
type state (line 10) | type state struct
function isTerminal (line 14) | func isTerminal(fd uintptr) bool {
function makeRaw (line 19) | func makeRaw(fd uintptr) (*State, error) {
function setState (line 43) | func setState(fd uintptr, state *State) error {
function getState (line 51) | func getState(fd uintptr) (*State, error) {
function restore (line 60) | func restore(fd uintptr, state *State) error {
function getSize (line 64) | func getSize(fd uintptr) (width, height int, err error) {
type passwordReader (line 73) | type passwordReader
method Read (line 75) | func (r passwordReader) Read(buf []byte) (int, error) {
function readPassword (line 79) | func readPassword(fd uintptr) ([]byte, error) {
FILE: vendor/github.com/charmbracelet/x/term/term_unix_bsd.go
constant ioctlReadTermios (line 9) | ioctlReadTermios = unix.TIOCGETA
constant ioctlWriteTermios (line 10) | ioctlWriteTermios = unix.TIOCSETA
FILE: vendor/github.com/charmbracelet/x/term/term_unix_other.go
constant ioctlReadTermios (line 9) | ioctlReadTermios = unix.TCGETS
constant ioctlWriteTermios (line 10) | ioctlWriteTermios = unix.TCSETS
FILE: vendor/github.com/charmbracelet/x/term/term_windows.go
type state (line 12) | type state struct
function isTerminal (line 16) | func isTerminal(fd uintptr) bool {
function makeRaw (line 22) | func makeRaw(fd uintptr) (*State, error) {
function setState (line 35) | func setState(fd uintptr, state *State) error {
function getState (line 43) | func getState(fd uintptr) (*State, error) {
function restore (line 51) | func restore(fd uintptr, state *State) error {
function getSize (line 55) | func getSize(fd uintptr) (width, height int, err error) {
function readPassword (line 63) | func readPassword(fd uintptr) ([]byte, error) {
FILE: vendor/github.com/charmbracelet/x/term/terminal.go
type File (line 9) | type File interface
FILE: vendor/github.com/charmbracelet/x/term/util.go
function readPasswordLine (line 13) | func readPasswordLine(reader io.Reader) ([]byte, error) {
FILE: vendor/github.com/erikgeiser/coninput/keycodes.go
type VirtualKeyCode (line 5) | type VirtualKeyCode
constant VK_LBUTTON (line 8) | VK_LBUTTON VirtualKeyCode = 0x01
constant VK_RBUTTON (line 9) | VK_RBUTTON VirtualKeyCode = 0x02
constant VK_CANCEL (line 10) | VK_CANCEL VirtualKeyCode = 0x03
constant VK_MBUTTON (line 11) | VK_MBUTTON VirtualKeyCode = 0x04
constant VK_XBUTTON1 (line 12) | VK_XBUTTON1 VirtualKeyCode = 0x05
constant VK_XBUTTON2 (line 13) | VK_XBUTTON2 VirtualKeyCode = 0x06
constant VK_BACK (line 14) | VK_BACK VirtualKeyCode = 0x08
constant VK_TAB (line 15) | VK_TAB VirtualKeyCode = 0x09
constant VK_CLEAR (line 16) | VK_CLEAR VirtualKeyCode = 0x0C
constant VK_RETURN (line 17) | VK_RETURN VirtualKeyCode = 0x0D
constant VK_SHIFT (line 18) | VK_SHIFT VirtualKeyCode = 0x10
constant VK_CONTROL (line 19) | VK_CONTROL VirtualKeyCode = 0x11
constant VK_MENU (line 20) | VK_MENU VirtualKeyCode = 0x12
constant VK_PAUSE (line 21) | VK_PAUSE VirtualKeyCode = 0x13
constant VK_CAPITAL (line 22) | VK_CAPITAL VirtualKeyCode = 0x14
constant VK_KANA (line 23) | VK_KANA VirtualKeyCode = 0x15
constant VK_HANGEUL (line 24) | VK_HANGEUL VirtualKeyCode = 0x15
constant VK_HANGUL (line 25) | VK_HANGUL VirtualKeyCode = 0x15
constant VK_IME_ON (line 26) | VK_IME_ON VirtualKeyCode = 0x16
constant VK_JUNJA (line 27) | VK_JUNJA VirtualKeyCode = 0x17
constant VK_FINAL (line 28) | VK_FINAL VirtualKeyCode = 0x18
constant VK_HANJA (line 29) | VK_HANJA VirtualKeyCode = 0x19
constant VK_KANJI (line 30) | VK_KANJI VirtualKeyCode = 0x19
constant VK_IME_OFF (line 31) | VK_IME_OFF VirtualKeyCode = 0x1A
constant VK_ESCAPE (line 32) | VK_ESCAPE VirtualKeyCode = 0x1B
constant VK_CONVERT (line 33) | VK_CONVERT VirtualKeyCode = 0x1C
constant VK_NONCONVERT (line 34) | VK_NONCONVERT VirtualKeyCode = 0x1D
constant VK_ACCEPT (line 35) | VK_ACCEPT VirtualKeyCode = 0x1E
constant VK_MODECHANGE (line 36) | VK_MODECHANGE VirtualKeyCode = 0x1F
constant VK_SPACE (line 37) | VK_SPACE VirtualKeyCode = 0x20
constant VK_PRIOR (line 38) | VK_PRIOR VirtualKeyCode = 0x21
constant VK_NEXT (line 39) | VK_NEXT VirtualKeyCode = 0x22
constant VK_END (line 40) | VK_END VirtualKeyCode = 0x23
constant VK_HOME (line 41) | VK_HOME VirtualKeyCode = 0x24
constant VK_LEFT (line 42) | VK_LEFT VirtualKeyCode = 0x25
constant VK_UP (line 43) | VK_UP VirtualKeyCode = 0x26
constant VK_RIGHT (line 44) | VK_RIGHT VirtualKeyCode = 0x27
constant VK_DOWN (line 45) | VK_DOWN VirtualKeyCode = 0x28
constant VK_SELECT (line 46) | VK_SELECT VirtualKeyCode = 0x29
constant VK_PRINT (line 47) | VK_PRINT VirtualKeyCode = 0x2A
constant VK_EXECUTE (line 48) | VK_EXECUTE VirtualKeyCode = 0x2B
constant VK_SNAPSHOT (line 49) | VK_SNAPSHOT VirtualKeyCode = 0x2C
constant VK_INSERT (line 50) | VK_INSERT VirtualKeyCode = 0x2D
constant VK_DELETE (line 51) | VK_DELETE VirtualKeyCode = 0x2E
constant VK_HELP (line 52) | VK_HELP VirtualKeyCode = 0x2F
constant VK_0 (line 53) | VK_0 VirtualKeyCode = 0x30
constant VK_1 (line 54) | VK_1 VirtualKeyCode = 0x31
constant VK_2 (line 55) | VK_2 VirtualKeyCode = 0x32
constant VK_3 (line 56) | VK_3 VirtualKeyCode = 0x33
constant VK_4 (line 57) | VK_4 VirtualKeyCode = 0x34
constant VK_5 (line 58) | VK_5 VirtualKeyCode = 0x35
constant VK_6 (line 59) | VK_6 VirtualKeyCode = 0x36
constant VK_7 (line 60) | VK_7 VirtualKeyCode = 0x37
constant VK_8 (line 61) | VK_8 VirtualKeyCode = 0x38
constant VK_9 (line 62) | VK_9 VirtualKeyCode = 0x39
constant VK_A (line 63) | VK_A VirtualKeyCode = 0x41
constant VK_B (line 64) | VK_B VirtualKeyCode = 0x42
constant VK_C (line 65) | VK_C VirtualKeyCode = 0x43
constant VK_D (line 66) | VK_D VirtualKeyCode = 0x44
constant VK_E (line 67) | VK_E VirtualKeyCode = 0x45
constant VK_F (line 68) | VK_F VirtualKeyCode = 0x46
constant VK_G (line 69) | VK_G VirtualKeyCode = 0x47
constant VK_H (line 70) | VK_H VirtualKeyCode = 0x48
constant VK_I (line 71) | VK_I VirtualKeyCode = 0x49
constant VK_J (line 72) | VK_J VirtualKeyCode = 0x4A
constant VK_K (line 73) | VK_K VirtualKeyCode = 0x4B
constant VK_L (line 74) | VK_L VirtualKeyCode = 0x4C
constant VK_M (line 75) | VK_M VirtualKeyCode = 0x4D
constant VK_N (line 76) | VK_N VirtualKeyCode = 0x4E
constant VK_O (line 77) | VK_O VirtualKeyCode = 0x4F
constant VK_P (line 78) | VK_P VirtualKeyCode = 0x50
constant VK_Q (line 79) | VK_Q VirtualKeyCode = 0x51
constant VK_R (line 80) | VK_R VirtualKeyCode = 0x52
constant VK_S (line 81) | VK_S VirtualKeyCode = 0x53
constant VK_T (line 82) | VK_T VirtualKeyCode = 0x54
constant VK_U (line 83) | VK_U VirtualKeyCode = 0x55
constant VK_V (line 84) | VK_V VirtualKeyCode = 0x56
constant VK_W (line 85) | VK_W VirtualKeyCode = 0x57
constant VK_X (line 86) | VK_X VirtualKeyCode = 0x58
constant VK_Y (line 87) | VK_Y VirtualKeyCode = 0x59
constant VK_Z (line 88) | VK_Z VirtualKeyCode = 0x5A
constant VK_LWIN (line 89) | VK_LWIN VirtualKeyCode = 0x5B
constant VK_RWIN (line 90) | VK_RWIN VirtualKeyCode = 0x5C
constant VK_APPS (line 91) | VK_APPS VirtualKeyCode = 0x5D
constant VK_SLEEP (line 92) | VK_SLEEP VirtualKeyCode = 0x5F
constant VK_NUMPAD0 (line 93) | VK_NUMPAD0 VirtualKeyCode = 0x60
constant VK_NUMPAD1 (line 94) | VK_NUMPAD1 VirtualKeyCode = 0x61
constant VK_NUMPAD2 (line 95) | VK_NUMPAD2 VirtualKeyCode = 0x62
constant VK_NUMPAD3 (line 96) | VK_NUMPAD3 VirtualKeyCode = 0x63
constant VK_NUMPAD4 (line 97) | VK_NUMPAD4 VirtualKeyCode = 0x64
constant VK_NUMPAD5 (line 98) | VK_NUMPAD5 VirtualKeyCode = 0x65
constant VK_NUMPAD6 (line 99) | VK_NUMPAD6 VirtualKeyCode = 0x66
constant VK_NUMPAD7 (line 100) | VK_NUMPAD7 VirtualKeyCode = 0x67
constant VK_NUMPAD8 (line 101) | VK_NUMPAD8 VirtualKeyCode = 0x68
constant VK_NUMPAD9 (line 102) | VK_NUMPAD9 VirtualKeyCode = 0x69
constant VK_MULTIPLY (line 103) | VK_MULTIPLY VirtualKeyCode = 0x6A
constant VK_ADD (line 104) | VK_ADD VirtualKeyCode = 0x6B
constant VK_SEPARATOR (line 105) | VK_SEPARATOR VirtualKeyCode = 0x6C
constant VK_SUBTRACT (line 106) | VK_SUBTRACT VirtualKeyCode = 0x6D
constant VK_DECIMAL (line 107) | VK_DECIMAL VirtualKeyCode = 0x6E
constant VK_DIVIDE (line 108) | VK_DIVIDE VirtualKeyCode = 0x6F
constant VK_F1 (line 109) | VK_F1 VirtualKeyCode = 0x70
constant VK_F2 (line 110) | VK_F2 VirtualKey
Copy disabled (too large)
Download .json
Condensed preview — 898 files, each showing path, character count, and a content snippet. Download the .json file for the full structured content (21,392K chars).
[
{
"path": ".gitattributes",
"chars": 50,
"preview": "Build/mpv.exe filter=lfs diff=lfs merge=lfs -text\n"
},
{
"path": ".github/ISSUE_TEMPLATE/bug_report.md",
"chars": 705,
"preview": "---\nname: Bug report\nabout: Create a report to help us improve\ntitle: ''\nlabels: bug, help wanted\nassignees: Wraient\n\n--"
},
{
"path": ".github/workflows/ci-cd.yml",
"chars": 11477,
"preview": "name: CI/CD Pipeline\n\non:\n push:\n branches:\n - main # Trigger on pushes to the main branch\n pull_request:\n "
},
{
"path": ".github/workflows/update-aur.yml",
"chars": 9696,
"preview": "name: Update AUR Package\n\non:\n release:\n types: [published]\n workflow_dispatch:\n\npermissions:\n contents: read\n\njob"
},
{
"path": "Build/buildlinux",
"chars": 64,
"preview": "#!/bin/bash\n\n./Build/buildlinux-arm64\n./Build/buildlinux-x86_64\n"
},
{
"path": "Build/buildlinux-arm64",
"chars": 383,
"preview": "VERSION=$(cat VERSION.txt)\nCGO_ENABLED=0 GOOS=linux GOARCH=arm64 go build -o curd-linux-arm64 -ldflags=\"-X main.version="
},
{
"path": "Build/buildlinux-x86_64",
"chars": 385,
"preview": "VERSION=$(cat VERSION.txt)\nCGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o curd-linux-x86_64 -ldflags=\"-X main.version"
},
{
"path": "Build/buildmac",
"chars": 61,
"preview": "#!/bin/bash\n\n./Build/buildmac-arm64\n./Build/buildmac-x86_64\n\n"
},
{
"path": "Build/buildmac-arm64",
"chars": 149,
"preview": "VERSION=$(cat VERSION.txt)\nCGO_ENABLED=0 GOOS=darwin GOARCH=arm64 go build -o curd-macos-arm64 -ldflags=\"-X main.version"
},
{
"path": "Build/buildmac-x86_64",
"chars": 160,
"preview": "VERSION=$(cat VERSION.txt)\nCGO_ENABLED=0 GOOS=darwin GOARCH=amd64 go build -o curd-macos-x86_64 -ldflags=\"-X main.versio"
},
{
"path": "Build/buildwindows",
"chars": 329,
"preview": "#!/bin/bash\n\n# Set required Windows build environment variables\nexport CGO_ENABLED=1\nexport GOOS=windows\n\n# Build for AR"
},
{
"path": "Build/buildwindows-arm64",
"chars": 381,
"preview": "VERSION=$(cat VERSION.txt)\nCGO_ENABLED=0 GOOS=windows GOARCH=arm64 go build -o curd-windows-arm64.exe -ldflags=\"-X main."
},
{
"path": "Build/buildwindows-x86_64",
"chars": 383,
"preview": "VERSION=$(cat VERSION.txt)\nCGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build -o curd-windows-x86_64.exe -ldflags=\"-X main"
},
{
"path": "Build/curd-windows-build.iss",
"chars": 932,
"preview": "[Setup]\r\nAppName=Curd Installer\r\nAppVersion=1.4.0\r\nDefaultDirName={userappdata}\\Curd\r\nPrivilegesRequired=lowest\r\nAllowNo"
},
{
"path": "Build/release",
"chars": 2939,
"preview": "#!/bin/bash\n\n# Ask for version number\nread -p \"Enter the version number: \" version\nrelease_folder=\"releases/curd-$versio"
},
{
"path": "Build/requirements.txt",
"chars": 83,
"preview": "mingw-w64-gcc # Build arm64 windows binary\nllvm-lipo # Build universal macos binary"
},
{
"path": "LICENSE",
"chars": 35149,
"preview": " GNU GENERAL PUBLIC LICENSE\n Version 3, 29 June 2007\n\n Copyright (C) 2007 Free "
},
{
"path": "PKGBUILD",
"chars": 530,
"preview": "# Maintainer: Wraient <rushikeshwastaken@gmail.com>\npkgname='curd'\npkgver=1.1.4\npkgrel=1\npkgdesc=\"Watch anime in CLI wit"
},
{
"path": "README.md",
"chars": 14976,
"preview": "# Curd\n\nA cli application to stream anime with [Anilist](https://anilist.co/) integration and Discord RPC written in gol"
},
{
"path": "VERSION.txt",
"chars": 5,
"preview": "1.4.0"
},
{
"path": "cmd/curd/main.go",
"chars": 36032,
"preview": "package main\n\nimport (\n\t\"flag\"\n\t\"fmt\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"runtime\"\n\t\"strconv\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/wraient"
},
{
"path": "flake.nix",
"chars": 783,
"preview": "{\n description = \"Watch anime in cli with Anilist Integration and Discord RPC \";\n\n inputs = {\n nixpkgs.url = \"githu"
},
{
"path": "go.mod",
"chars": 1734,
"preview": "module github.com/wraient/curd\n\ngo 1.21\n\nrequire (\n\tgithub.com/Microsoft/go-winio v0.6.2\n\tgithub.com/charmbracelet/bubbl"
},
{
"path": "go.sum",
"chars": 6382,
"preview": "github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY=\ngithub.com/Microsoft/go-winio v0.6."
},
{
"path": "internal/anilist.go",
"chars": 29892,
"preview": "package internal\n\nimport (\n\t\"bytes\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"io\"\n\t\"net/http\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"sort\"\n\t\"strconv\"\n"
},
{
"path": "internal/anilist_cache.go",
"chars": 7837,
"preview": "package internal\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"strconv\"\n\t\"sync\"\n\t\"time\"\n)\n\nconst animeListC"
},
{
"path": "internal/anime_list.go",
"chars": 5903,
"preview": "package internal\n\nimport (\n\t\"bytes\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"io\"\n\t\"net/http\"\n\t\"path/filepath\"\n\t\"strings\"\n)\n\ntype anime "
},
{
"path": "internal/aniskip.go",
"chars": 3927,
"preview": "package internal\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"io\"\n\t\"math\"\n\t\"net/http\"\n)\n\n// skipTimesResponse struct to hold the "
},
{
"path": "internal/config.go",
"chars": 19162,
"preview": "package internal\n\nimport (\n\t\"bufio\"\n\t\"context\"\n\t\"encoding/json\"\n\t\"fmt\"\n\n\t// \"io\"\n\t\"net/http\"\n\t\"net/url\"\n\t\"os\"\n\t\"path/fil"
},
{
"path": "internal/curd.go",
"chars": 69810,
"preview": "package internal\n\nimport (\n\t\"bufio\"\n\t\"crypto/md5\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"io\"\n\t\"net/http\"\n\t\"os\"\n\t\"os/exec\"\n\t\"path/file"
},
{
"path": "internal/discord.go",
"chars": 4207,
"preview": "package internal\n\nimport (\n\t\"fmt\"\n\t\"github.com/tr1xem/go-discordrpc/client\"\n\t\"time\"\n)\n\nvar discordClient *client.Client\n"
},
{
"path": "internal/episode_list.go",
"chars": 3398,
"preview": "package internal\n\nimport (\n\t\"bytes\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"io\"\n\t\"net/http\"\n\t\"sort\"\n\t\"strconv\"\n)\n\ntype episodesRespons"
},
{
"path": "internal/episode_url.go",
"chars": 21577,
"preview": "package internal\n\nimport (\n\t\"bytes\"\n\t\"crypto/aes\"\n\t\"crypto/cipher\"\n\t\"crypto/sha256\"\n\t\"encoding/base64\"\n\t\"encoding/binary"
},
{
"path": "internal/filler_list.go",
"chars": 2212,
"preview": "package internal\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"net/http\"\n\t\"time\"\n)\n\ntype AnimeFillerListEpisode struct {\n\tEpisodeI"
},
{
"path": "internal/globals.go",
"chars": 510,
"preview": "package internal\n\nvar (\n\tglobalAnime *Anime\n\tglobalLogFile string\n)\n\n// SetGlobalAnime sets the global anime reference"
},
{
"path": "internal/http_client.go",
"chars": 557,
"preview": "package internal\n\nimport (\n\t\"net/http\"\n\t\"net/http/cookiejar\"\n\t\"net/url\"\n\t\"time\"\n)\n\nvar sharedHTTPClient *http.Client\n\nfu"
},
{
"path": "internal/jikan.go",
"chars": 5141,
"preview": "package internal\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"io\"\n\t\"net/http\"\n)\n\n// GetEpisodeData fetches episode data for a giv"
},
{
"path": "internal/links.go",
"chars": 1031,
"preview": "package internal\n\nimport \"strings\"\n\n// LinkPriorities defines the order of priority for link domains\nvar LinkPriorities "
},
{
"path": "internal/localTracking.go",
"chars": 12973,
"preview": "package internal\n\nimport (\n\t\"bufio\"\n\t\"encoding/csv\"\n\t\"fmt\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"strconv\"\n\t\"strings\"\n\t\"time\"\n)\n\n// Fu"
},
{
"path": "internal/player.go",
"chars": 26609,
"preview": "package internal\n\nimport (\n\t\"crypto/rand\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"os\"\n\t\"os/exec\"\n\t\"path/filepath\"\n\t\"runtime\"\n\t\"strings"
},
{
"path": "internal/provider.go",
"chars": 1087,
"preview": "package internal\n\n// Provider interface defines methods for an anime provider.\ntype Provider interface {\n\tName() string\n"
},
{
"path": "internal/provider_allanime.go",
"chars": 523,
"preview": "package internal\n\ntype AllanimeProvider struct{}\n\nfunc (p *AllanimeProvider) Name() string {\n\treturn \"allanime\"\n}\n\nfunc "
},
{
"path": "internal/provider_animepahe.go",
"chars": 13467,
"preview": "package internal\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"io\"\n\t\"net/http\"\n\t\"net/url\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"regexp\"\n\t\"sort\""
},
{
"path": "internal/rofi.go",
"chars": 1459,
"preview": "package internal\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\t\"os/exec\"\n\t\"path/filepath\"\n\t\"strings\"\n)\n\nfunc GetTokenFromRofi() (string, er"
},
{
"path": "internal/selection_menu.go",
"chars": 20014,
"preview": "package internal\n\nimport (\n\t\"bytes\"\n\t\"crypto/md5\"\n\t\"fmt\"\n\t\"io\"\n\t\"net/http\"\n\t\"os\"\n\t\"os/exec\"\n\t\"path/filepath\"\n\t\"reflect\"\n"
},
{
"path": "internal/structs.go",
"chars": 3848,
"preview": "package internal\n\ntype AnimeTitle struct {\n\tRomaji string `json:\"title_romanji\"`\n\tEnglish string `json:\"title\"`\n\tJapa"
},
{
"path": "internal/unix_ipc.go",
"chars": 242,
"preview": "//go:build !windows\n// +build !windows\n\npackage internal\n\nimport (\n\t\"net\"\n)\n\nfunc connectToPipe(ipcSocketPath string) (n"
},
{
"path": "internal/windows_ipc.go",
"chars": 277,
"preview": "//go:build windows\n// +build windows\n\npackage internal\n\nimport (\n\t\"net\"\n\n\t\"github.com/Microsoft/go-winio\"\n)\n\nfunc connec"
},
{
"path": "package.nix",
"chars": 1123,
"preview": "{\n buildGoModule,\n lib,\n makeBinaryWrapper,\n mpv,\n rofi,\n ueberzugpp,\n withMpv ? true,\n withRofi ? false,\n with"
},
{
"path": "rofi/contextselect.rasi",
"chars": 2236,
"preview": "configuration {\n font: \"Sans 12\";\n line-margin: 10;\n display-drun: \"\";\n}\n\n* {\n background: #000000; /* "
},
{
"path": "rofi/selectanime.rasi",
"chars": 1833,
"preview": "configuration {\n font: \"Sans 12\";\n line-margin: 10;\n display-drun: \"\";\n}\n\n* {\n background: #000000; /* "
},
{
"path": "rofi/selectanimepreview.rasi",
"chars": 6560,
"preview": "// Colours\n* {\n background-color: transparent; /* Transparent background for the global UI */\n back"
},
{
"path": "rofi/userinput.rasi",
"chars": 1033,
"preview": "* {\n background: #000000;\n background-alt: #1a1a1a;\n foreground: #CCCCCC;\n selected: #3584E4;\n"
},
{
"path": "vendor/github.com/Microsoft/go-winio/.gitattributes",
"chars": 18,
"preview": "* text=auto eol=lf"
},
{
"path": "vendor/github.com/Microsoft/go-winio/.golangci.yml",
"chars": 4244,
"preview": "linters:\n enable:\n # style\n - containedctx # struct contains a context\n - dupl # duplicate code\n - errname "
},
{
"path": "vendor/github.com/Microsoft/go-winio/CODEOWNERS",
"chars": 29,
"preview": " * @microsoft/containerplat\n"
},
{
"path": "vendor/github.com/Microsoft/go-winio/LICENSE",
"chars": 1077,
"preview": "The MIT License (MIT)\n\nCopyright (c) 2015 Microsoft\n\nPermission is hereby granted, free of charge, to any person obtaini"
},
{
"path": "vendor/github.com/Microsoft/go-winio/README.md",
"chars": 3771,
"preview": "# go-winio [](https://github.co"
},
{
"path": "vendor/github.com/Microsoft/go-winio/SECURITY.md",
"chars": 2757,
"preview": "<!-- BEGIN MICROSOFT SECURITY.MD V0.0.7 BLOCK -->\n\n## Security\n\nMicrosoft takes the security of our software products an"
},
{
"path": "vendor/github.com/Microsoft/go-winio/backup.go",
"chars": 8330,
"preview": "//go:build windows\n// +build windows\n\npackage winio\n\nimport (\n\t\"encoding/binary\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"os\"\n\t\"runtime\""
},
{
"path": "vendor/github.com/Microsoft/go-winio/doc.go",
"chars": 1076,
"preview": "// This package provides utilities for efficiently performing Win32 IO operations in Go.\n// Currently, this package is p"
},
{
"path": "vendor/github.com/Microsoft/go-winio/ea.go",
"chars": 3178,
"preview": "package winio\n\nimport (\n\t\"bytes\"\n\t\"encoding/binary\"\n\t\"errors\"\n)\n\ntype fileFullEaInformation struct {\n\tNextEntryOffset ui"
},
{
"path": "vendor/github.com/Microsoft/go-winio/file.go",
"chars": 8132,
"preview": "//go:build windows\n// +build windows\n\npackage winio\n\nimport (\n\t\"errors\"\n\t\"io\"\n\t\"runtime\"\n\t\"sync\"\n\t\"sync/atomic\"\n\t\"syscal"
},
{
"path": "vendor/github.com/Microsoft/go-winio/fileinfo.go",
"chars": 3619,
"preview": "//go:build windows\n// +build windows\n\npackage winio\n\nimport (\n\t\"os\"\n\t\"runtime\"\n\t\"unsafe\"\n\n\t\"golang.org/x/sys/windows\"\n)\n"
},
{
"path": "vendor/github.com/Microsoft/go-winio/hvsock.go",
"chars": 15948,
"preview": "//go:build windows\n// +build windows\n\npackage winio\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"net\"\n\t\"os\"\n\t\"time\"\n\t\"u"
},
{
"path": "vendor/github.com/Microsoft/go-winio/internal/fs/doc.go",
"chars": 68,
"preview": "// This package contains Win32 filesystem functionality.\npackage fs\n"
},
{
"path": "vendor/github.com/Microsoft/go-winio/internal/fs/fs.go",
"chars": 10077,
"preview": "//go:build windows\n\npackage fs\n\nimport (\n\t\"golang.org/x/sys/windows\"\n\n\t\"github.com/Microsoft/go-winio/internal/stringbuf"
},
{
"path": "vendor/github.com/Microsoft/go-winio/internal/fs/security.go",
"chars": 469,
"preview": "package fs\n\n// https://learn.microsoft.com/en-us/windows/win32/api/winnt/ne-winnt-security_impersonation_level\ntype Secu"
},
{
"path": "vendor/github.com/Microsoft/go-winio/internal/fs/zsyscall_windows.go",
"chars": 1754,
"preview": "//go:build windows\n\n// Code generated by 'go generate' using \"github.com/Microsoft/go-winio/tools/mkwinsyscall\"; DO NOT "
},
{
"path": "vendor/github.com/Microsoft/go-winio/internal/socket/rawaddr.go",
"chars": 723,
"preview": "package socket\n\nimport (\n\t\"unsafe\"\n)\n\n// RawSockaddr allows structs to be used with [Bind] and [ConnectEx]. The\n// struc"
},
{
"path": "vendor/github.com/Microsoft/go-winio/internal/socket/socket.go",
"chars": 4952,
"preview": "//go:build windows\n\npackage socket\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"net\"\n\t\"sync\"\n\t\"syscall\"\n\t\"unsafe\"\n\n\t\"github.com/Microsof"
},
{
"path": "vendor/github.com/Microsoft/go-winio/internal/socket/zsyscall_windows.go",
"chars": 1662,
"preview": "//go:build windows\n\n// Code generated by 'go generate' using \"github.com/Microsoft/go-winio/tools/mkwinsyscall\"; DO NOT "
},
{
"path": "vendor/github.com/Microsoft/go-winio/internal/stringbuffer/wstring.go",
"chars": 3471,
"preview": "package stringbuffer\n\nimport (\n\t\"sync\"\n\t\"unicode/utf16\"\n)\n\n// TODO: worth exporting and using in mkwinsyscall?\n\n// Uint1"
},
{
"path": "vendor/github.com/Microsoft/go-winio/pipe.go",
"chars": 16501,
"preview": "//go:build windows\n// +build windows\n\npackage winio\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"net\"\n\t\"os\"\n\t\"runtime\"\n"
},
{
"path": "vendor/github.com/Microsoft/go-winio/pkg/guid/guid.go",
"chars": 6198,
"preview": "// Package guid provides a GUID type. The backing structure for a GUID is\n// identical to that used by the golang.org/x/"
},
{
"path": "vendor/github.com/Microsoft/go-winio/pkg/guid/guid_nonwindows.go",
"chars": 444,
"preview": "//go:build !windows\n// +build !windows\n\npackage guid\n\n// GUID represents a GUID/UUID. It has the same structure as\n// go"
},
{
"path": "vendor/github.com/Microsoft/go-winio/pkg/guid/guid_windows.go",
"chars": 420,
"preview": "//go:build windows\n// +build windows\n\npackage guid\n\nimport \"golang.org/x/sys/windows\"\n\n// GUID represents a GUID/UUID. I"
},
{
"path": "vendor/github.com/Microsoft/go-winio/pkg/guid/variant_string.go",
"chars": 747,
"preview": "// Code generated by \"stringer -type=Variant -trimprefix=Variant -linecomment\"; DO NOT EDIT.\n\npackage guid\n\nimport \"strc"
},
{
"path": "vendor/github.com/Microsoft/go-winio/privilege.go",
"chars": 5565,
"preview": "//go:build windows\n// +build windows\n\npackage winio\n\nimport (\n\t\"bytes\"\n\t\"encoding/binary\"\n\t\"fmt\"\n\t\"runtime\"\n\t\"sync\"\n\t\"un"
},
{
"path": "vendor/github.com/Microsoft/go-winio/reparse.go",
"chars": 3525,
"preview": "//go:build windows\n// +build windows\n\npackage winio\n\nimport (\n\t\"bytes\"\n\t\"encoding/binary\"\n\t\"fmt\"\n\t\"strings\"\n\t\"unicode/ut"
},
{
"path": "vendor/github.com/Microsoft/go-winio/sd.go",
"chars": 4368,
"preview": "//go:build windows\n// +build windows\n\npackage winio\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"unsafe\"\n\n\t\"golang.org/x/sys/windows\"\n)\n"
},
{
"path": "vendor/github.com/Microsoft/go-winio/syscall.go",
"chars": 140,
"preview": "//go:build windows\n\npackage winio\n\n//go:generate go run github.com/Microsoft/go-winio/tools/mkwinsyscall -output zsyscal"
},
{
"path": "vendor/github.com/Microsoft/go-winio/zsyscall_windows.go",
"chars": 14895,
"preview": "//go:build windows\n\n// Code generated by 'go generate' using \"github.com/Microsoft/go-winio/tools/mkwinsyscall\"; DO NOT "
},
{
"path": "vendor/github.com/aymanbagabas/go-osc52/v2/LICENSE",
"chars": 1070,
"preview": "MIT License\n\nCopyright (c) 2022 Ayman Bagabas\n\nPermission is hereby granted, free of charge, to any person obtaining a c"
},
{
"path": "vendor/github.com/aymanbagabas/go-osc52/v2/README.md",
"chars": 2370,
"preview": "\n# go-osc52\n\n<p>\n <a href=\"https://github.com/aymanbagabas/go-osc52/releases\"><img src=\"https://img.shields.io/github"
},
{
"path": "vendor/github.com/aymanbagabas/go-osc52/v2/osc52.go",
"chars": 7978,
"preview": "// OSC52 is a terminal escape sequence that allows copying text to the clipboard.\n//\n// The sequence consists of the fol"
},
{
"path": "vendor/github.com/charmbracelet/bubbletea/.gitattributes",
"chars": 15,
"preview": "*.golden -text\n"
},
{
"path": "vendor/github.com/charmbracelet/bubbletea/.golangci-soft.yml",
"chars": 588,
"preview": "run:\n tests: false\n issues-exit-code: 0\n\nissues:\n include:\n - EXC0001\n - EXC0005\n - EXC0011\n - EXC0012\n "
},
{
"path": "vendor/github.com/charmbracelet/bubbletea/.golangci.yml",
"chars": 365,
"preview": "run:\n tests: false\n\nissues:\n include:\n - EXC0001\n - EXC0005\n - EXC0011\n - EXC0012\n - EXC0013\n\n max-iss"
},
{
"path": "vendor/github.com/charmbracelet/bubbletea/.goreleaser.yml",
"chars": 168,
"preview": "# yaml-language-server: $schema=https://goreleaser.com/static/schema-pro.json\nversion: 2\nincludes:\n - from_url:\n u"
},
{
"path": "vendor/github.com/charmbracelet/bubbletea/LICENSE",
"chars": 1080,
"preview": "MIT License\n\nCopyright (c) 2020-2023 Charmbracelet, Inc\n\nPermission is hereby granted, free of charge, to any person obt"
},
{
"path": "vendor/github.com/charmbracelet/bubbletea/README.md",
"chars": 14705,
"preview": "# Bubble Tea\n\n<p>\n <a href=\"https://stuff.charm.sh/bubbletea/bubbletea-4k.png\"><img src=\"https://github.com/charmbrac"
},
{
"path": "vendor/github.com/charmbracelet/bubbletea/commands.go",
"chars": 5570,
"preview": "package tea\n\nimport (\n\t\"time\"\n)\n\n// Batch performs a bunch of commands concurrently with no ordering guarantees\n// about"
},
{
"path": "vendor/github.com/charmbracelet/bubbletea/exec.go",
"chars": 3548,
"preview": "package tea\n\nimport (\n\t\"io\"\n\t\"os\"\n\t\"os/exec\"\n)\n\n// execMsg is used internally to run an ExecCommand sent with Exec.\ntype"
},
{
"path": "vendor/github.com/charmbracelet/bubbletea/focus.go",
"chars": 247,
"preview": "package tea\n\n// FocusMsg represents a terminal focus message.\n// This occurs when the terminal gains focus.\ntype FocusMs"
},
{
"path": "vendor/github.com/charmbracelet/bubbletea/inputreader_other.go",
"chars": 212,
"preview": "//go:build !windows\n// +build !windows\n\npackage tea\n\nimport (\n\t\"io\"\n\n\t\"github.com/muesli/cancelreader\"\n)\n\nfunc newInputR"
},
{
"path": "vendor/github.com/charmbracelet/bubbletea/inputreader_windows.go",
"chars": 2430,
"preview": "//go:build windows\n// +build windows\n\npackage tea\n\nimport (\n\t\"fmt\"\n\t\"io\"\n\t\"os\"\n\t\"sync\"\n\n\t\"github.com/charmbracelet/x/ter"
},
{
"path": "vendor/github.com/charmbracelet/bubbletea/key.go",
"chars": 21811,
"preview": "package tea\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"io\"\n\t\"regexp\"\n\t\"strings\"\n\t\"unicode/utf8\"\n)\n\n// KeyMsg contains information abo"
},
{
"path": "vendor/github.com/charmbracelet/bubbletea/key_other.go",
"chars": 204,
"preview": "//go:build !windows\n// +build !windows\n\npackage tea\n\nimport (\n\t\"context\"\n\t\"io\"\n)\n\nfunc readInputs(ctx context.Context, m"
},
{
"path": "vendor/github.com/charmbracelet/bubbletea/key_sequences.go",
"chars": 3538,
"preview": "package tea\n\nimport (\n\t\"bytes\"\n\t\"sort\"\n\t\"unicode/utf8\"\n)\n\n// extSequences is used by the map-based algorithm below. It c"
},
{
"path": "vendor/github.com/charmbracelet/bubbletea/key_windows.go",
"chars": 8729,
"preview": "//go:build windows\n// +build windows\n\npackage tea\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"io\"\n\n\t\"github.com/erikgeiser/coninput\"\n\t"
},
{
"path": "vendor/github.com/charmbracelet/bubbletea/logging.go",
"chars": 1391,
"preview": "package tea\n\nimport (\n\t\"fmt\"\n\t\"io\"\n\t\"log\"\n\t\"os\"\n\t\"unicode\"\n)\n\n// LogToFile sets up default logging to log to a file. Thi"
},
{
"path": "vendor/github.com/charmbracelet/bubbletea/mouse.go",
"chars": 7905,
"preview": "package tea\n\nimport \"strconv\"\n\n// MouseMsg contains information about a mouse event and are sent to a programs\n// update"
},
{
"path": "vendor/github.com/charmbracelet/bubbletea/nil_renderer.go",
"chars": 1330,
"preview": "package tea\n\ntype nilRenderer struct{}\n\nfunc (n nilRenderer) start() {}\nfunc (n nilRenderer) stop() "
},
{
"path": "vendor/github.com/charmbracelet/bubbletea/options.go",
"chars": 8291,
"preview": "package tea\n\nimport (\n\t\"context\"\n\t\"io\"\n\t\"sync/atomic\"\n)\n\n// ProgramOption is used to set options when initializing a Pro"
},
{
"path": "vendor/github.com/charmbracelet/bubbletea/renderer.go",
"chars": 2417,
"preview": "package tea\n\n// renderer is the interface for Bubble Tea renderers.\ntype renderer interface {\n\t// Start the renderer.\n\ts"
},
{
"path": "vendor/github.com/charmbracelet/bubbletea/screen.go",
"chars": 8767,
"preview": "package tea\n\n// WindowSizeMsg is used to report the terminal size. It's sent to Update once\n// initially and then on eve"
},
{
"path": "vendor/github.com/charmbracelet/bubbletea/signals_unix.go",
"chars": 662,
"preview": "//go:build darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris || aix || zos\n// +build darwin dragon"
},
{
"path": "vendor/github.com/charmbracelet/bubbletea/signals_windows.go",
"chars": 225,
"preview": "//go:build windows\n// +build windows\n\npackage tea\n\n// listenForResize is not available on windows because windows does n"
},
{
"path": "vendor/github.com/charmbracelet/bubbletea/standard_renderer.go",
"chars": 20842,
"preview": "package tea\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\t\"io\"\n\t\"strings\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/charmbracelet/x/ansi\"\n\t\"github.com/"
},
{
"path": "vendor/github.com/charmbracelet/bubbletea/tea.go",
"chars": 20950,
"preview": "// Package tea provides a framework for building rich terminal user interfaces\n// based on the paradigms of The Elm Arch"
},
{
"path": "vendor/github.com/charmbracelet/bubbletea/tea_init.go",
"chars": 712,
"preview": "package tea\n\nimport (\n\t\"github.com/charmbracelet/lipgloss\"\n)\n\nfunc init() {\n\t// XXX: This is a workaround to make assure"
},
{
"path": "vendor/github.com/charmbracelet/bubbletea/tty.go",
"chars": 2951,
"preview": "package tea\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"time\"\n\n\t\"github.com/charmbracelet/x/term\"\n\t\"github.com/muesli/cancelreade"
},
{
"path": "vendor/github.com/charmbracelet/bubbletea/tty_unix.go",
"chars": 1094,
"preview": "//go:build darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris || aix || zos\n// +build darwin dragon"
},
{
"path": "vendor/github.com/charmbracelet/bubbletea/tty_windows.go",
"chars": 1707,
"preview": "//go:build windows\n// +build windows\n\npackage tea\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\n\t\"github.com/charmbracelet/x/term\"\n\t\"golang.or"
},
{
"path": "vendor/github.com/charmbracelet/lipgloss/.golangci-soft.yml",
"chars": 582,
"preview": "run:\n tests: false\n\nissues:\n include:\n - EXC0001\n - EXC0005\n - EXC0011\n - EXC0012\n - EXC0013\n\n max-iss"
},
{
"path": "vendor/github.com/charmbracelet/lipgloss/.golangci.yml",
"chars": 365,
"preview": "run:\n tests: false\n\nissues:\n include:\n - EXC0001\n - EXC0005\n - EXC0011\n - EXC0012\n - EXC0013\n\n max-iss"
},
{
"path": "vendor/github.com/charmbracelet/lipgloss/.goreleaser.yml",
"chars": 158,
"preview": "includes:\n - from_url:\n url: charmbracelet/meta/main/goreleaser-lib.yaml\n# yaml-language-server: $schema=https://g"
},
{
"path": "vendor/github.com/charmbracelet/lipgloss/LICENSE",
"chars": 1080,
"preview": "MIT License\n\nCopyright (c) 2021-2023 Charmbracelet, Inc\n\nPermission is hereby granted, free of charge, to any person obt"
},
{
"path": "vendor/github.com/charmbracelet/lipgloss/README.md",
"chars": 20328,
"preview": "# Lip Gloss\n\n<p>\n <a href=\"https://stuff.charm.sh/lipgloss/lipgloss-mascot-2k.png\"><img width=\"340\" alt=\"Lip Gloss ti"
},
{
"path": "vendor/github.com/charmbracelet/lipgloss/align.go",
"chars": 2195,
"preview": "package lipgloss\n\nimport (\n\t\"strings\"\n\n\t\"github.com/charmbracelet/x/ansi\"\n\t\"github.com/muesli/termenv\"\n)\n\n// Perform tex"
},
{
"path": "vendor/github.com/charmbracelet/lipgloss/ansi_unix.go",
"chars": 146,
"preview": "//go:build !windows\n// +build !windows\n\npackage lipgloss\n\n// enableLegacyWindowsANSI is only needed on Windows.\nfunc ena"
},
{
"path": "vendor/github.com/charmbracelet/lipgloss/ansi_windows.go",
"chars": 485,
"preview": "//go:build windows\n// +build windows\n\npackage lipgloss\n\nimport (\n\t\"sync\"\n\n\t\"github.com/muesli/termenv\"\n)\n\nvar enableANSI"
},
{
"path": "vendor/github.com/charmbracelet/lipgloss/borders.go",
"chars": 10223,
"preview": "package lipgloss\n\nimport (\n\t\"strings\"\n\n\t\"github.com/charmbracelet/x/ansi\"\n\t\"github.com/muesli/termenv\"\n\t\"github.com/rivo"
},
{
"path": "vendor/github.com/charmbracelet/lipgloss/color.go",
"chars": 4906,
"preview": "package lipgloss\n\nimport (\n\t\"strconv\"\n\n\t\"github.com/muesli/termenv\"\n)\n\n// TerminalColor is a color intended to be render"
},
{
"path": "vendor/github.com/charmbracelet/lipgloss/get.go",
"chars": 15879,
"preview": "package lipgloss\n\nimport (\n\t\"strings\"\n\n\t\"github.com/charmbracelet/x/ansi\"\n)\n\n// GetBold returns the style's bold value. "
},
{
"path": "vendor/github.com/charmbracelet/lipgloss/join.go",
"chars": 4128,
"preview": "package lipgloss\n\nimport (\n\t\"math\"\n\t\"strings\"\n\n\t\"github.com/charmbracelet/x/ansi\"\n)\n\n// JoinHorizontal is a utility func"
},
{
"path": "vendor/github.com/charmbracelet/lipgloss/position.go",
"chars": 4392,
"preview": "package lipgloss\n\nimport (\n\t\"math\"\n\t\"strings\"\n\n\t\"github.com/charmbracelet/x/ansi\"\n)\n\n// Position represents a position a"
},
{
"path": "vendor/github.com/charmbracelet/lipgloss/renderer.go",
"chars": 5125,
"preview": "package lipgloss\n\nimport (\n\t\"io\"\n\t\"sync\"\n\n\t\"github.com/muesli/termenv\"\n)\n\n// We're manually creating the struct here to "
},
{
"path": "vendor/github.com/charmbracelet/lipgloss/runes.go",
"chars": 891,
"preview": "package lipgloss\n\nimport (\n\t\"strings\"\n)\n\n// StyleRunes apply a given style to runes at the given indices in the string.\n"
},
{
"path": "vendor/github.com/charmbracelet/lipgloss/set.go",
"chars": 22583,
"preview": "package lipgloss\n\n// Set a value on the underlying rules map.\nfunc (s *Style) set(key propKey, value interface{}) {\n\t// "
},
{
"path": "vendor/github.com/charmbracelet/lipgloss/size.go",
"chars": 1166,
"preview": "package lipgloss\n\nimport (\n\t\"strings\"\n\n\t\"github.com/charmbracelet/x/ansi\"\n)\n\n// Width returns the cell width of characte"
},
{
"path": "vendor/github.com/charmbracelet/lipgloss/style.go",
"chars": 13074,
"preview": "package lipgloss\n\nimport (\n\t\"strings\"\n\t\"unicode\"\n\n\t\"github.com/charmbracelet/x/ansi\"\n\t\"github.com/muesli/termenv\"\n)\n\ncon"
},
{
"path": "vendor/github.com/charmbracelet/lipgloss/unset.go",
"chars": 8184,
"preview": "package lipgloss\n\n// unset unsets a property from a style.\nfunc (s *Style) unset(key propKey) {\n\ts.props = s.props.unset"
},
{
"path": "vendor/github.com/charmbracelet/lipgloss/whitespace.go",
"chars": 1993,
"preview": "package lipgloss\n\nimport (\n\t\"strings\"\n\n\t\"github.com/charmbracelet/x/ansi\"\n\t\"github.com/muesli/termenv\"\n)\n\n// whitespace "
},
{
"path": "vendor/github.com/charmbracelet/x/ansi/LICENSE",
"chars": 1076,
"preview": "MIT License\n\nCopyright (c) 2023 Charmbracelet, Inc.\n\nPermission is hereby granted, free of charge, to any person obtaini"
},
{
"path": "vendor/github.com/charmbracelet/x/ansi/ansi.go",
"chars": 279,
"preview": "package ansi\n\nimport \"io\"\n\n// Execute is a function that \"execute\" the given escape sequence by writing it\n// to the pro"
},
{
"path": "vendor/github.com/charmbracelet/x/ansi/ascii.go",
"chars": 148,
"preview": "package ansi\n\nconst (\n\t// SP is the space character (Char: \\x20).\n\tSP = 0x20\n\t// DEL is the delete character (Caret: ^?,"
},
{
"path": "vendor/github.com/charmbracelet/x/ansi/background.go",
"chars": 4641,
"preview": "package ansi\n\nimport (\n\t\"fmt\"\n\t\"image/color\"\n)\n\n// Colorizer is a [color.Color] interface that can be formatted as a str"
},
{
"path": "vendor/github.com/charmbracelet/x/ansi/c0.go",
"chars": 2446,
"preview": "package ansi\n\n// C0 control characters.\n//\n// These range from (0x00-0x1F) as defined in ISO 646 (ASCII).\n// See: https:"
},
{
"path": "vendor/github.com/charmbracelet/x/ansi/c1.go",
"chars": 1998,
"preview": "package ansi\n\n// C1 control characters.\n//\n// These range from (0x80-0x9F) as defined in ISO 6429 (ECMA-48).\n// See: htt"
},
{
"path": "vendor/github.com/charmbracelet/x/ansi/charset.go",
"chars": 1537,
"preview": "package ansi\n\n// SelectCharacterSet sets the G-set character designator to the specified\n// character set.\n//\n//\tESC Ps "
},
{
"path": "vendor/github.com/charmbracelet/x/ansi/clipboard.go",
"chars": 2365,
"preview": "package ansi\n\nimport \"encoding/base64\"\n\n// Clipboard names.\nconst (\n\tSystemClipboard = 'c'\n\tPrimaryClipboard = 'p'\n)\n\n/"
},
{
"path": "vendor/github.com/charmbracelet/x/ansi/color.go",
"chars": 4424,
"preview": "package ansi\n\nimport (\n\t\"image/color\"\n)\n\n// Technically speaking, the 16 basic ANSI colors are arbitrary and can be\n// c"
},
{
"path": "vendor/github.com/charmbracelet/x/ansi/ctrl.go",
"chars": 3654,
"preview": "package ansi\n\nimport (\n\t\"strconv\"\n\t\"strings\"\n)\n\n// RequestNameVersion (XTVERSION) is a control sequence that requests th"
},
{
"path": "vendor/github.com/charmbracelet/x/ansi/cursor.go",
"chars": 15067,
"preview": "package ansi\n\nimport \"strconv\"\n\n// SaveCursor (DECSC) is an escape sequence that saves the current cursor\n// position.\n/"
},
{
"path": "vendor/github.com/charmbracelet/x/ansi/cwd.go",
"chars": 758,
"preview": "package ansi\n\nimport (\n\t\"net/url\"\n\t\"path\"\n)\n\n// NotifyWorkingDirectory returns a sequence that notifies the terminal\n// "
},
{
"path": "vendor/github.com/charmbracelet/x/ansi/doc.go",
"chars": 277,
"preview": "// Package ansi defines common ANSI escape sequences based on the ECMA-48\n// specs.\n//\n// All sequences use 7-bit C1 con"
},
{
"path": "vendor/github.com/charmbracelet/x/ansi/focus.go",
"chars": 288,
"preview": "package ansi\n\n// Focus is an escape sequence to notify the terminal that it has focus.\n// This is used with [FocusEventM"
},
{
"path": "vendor/github.com/charmbracelet/x/ansi/graphics.go",
"chars": 5323,
"preview": "package ansi\n\nimport (\n\t\"bytes\"\n\t\"encoding/base64\"\n\t\"errors\"\n\t\"fmt\"\n\t\"image\"\n\t\"io\"\n\t\"os\"\n\t\"strings\"\n\n\t\"github.com/charmb"
},
{
"path": "vendor/github.com/charmbracelet/x/ansi/hyperlink.go",
"chars": 733,
"preview": "package ansi\n\nimport \"strings\"\n\n// SetHyperlink returns a sequence for starting a hyperlink.\n//\n//\tOSC 8 ; Params ; Uri "
},
{
"path": "vendor/github.com/charmbracelet/x/ansi/iterm2.go",
"chars": 426,
"preview": "package ansi\n\nimport \"fmt\"\n\n// ITerm2 returns a sequence that uses the iTerm2 proprietary protocol. Use the\n// iterm2 pa"
},
{
"path": "vendor/github.com/charmbracelet/x/ansi/keypad.go",
"chars": 728,
"preview": "package ansi\n\n// Keypad Application Mode (DECKPAM) is a mode that determines whether the\n// keypad sends application seq"
},
{
"path": "vendor/github.com/charmbracelet/x/ansi/kitty/decoder.go",
"chars": 1876,
"preview": "package kitty\n\nimport (\n\t\"compress/zlib\"\n\t\"fmt\"\n\t\"image\"\n\t\"image/color\"\n\t\"image/png\"\n\t\"io\"\n)\n\n// Decoder is a decoder fo"
},
{
"path": "vendor/github.com/charmbracelet/x/ansi/kitty/encoder.go",
"chars": 1365,
"preview": "package kitty\n\nimport (\n\t\"compress/zlib\"\n\t\"fmt\"\n\t\"image\"\n\t\"image/png\"\n\t\"io\"\n)\n\n// Encoder is an encoder for the Kitty gr"
},
{
"path": "vendor/github.com/charmbracelet/x/ansi/kitty/graphics.go",
"chars": 6783,
"preview": "package kitty\n\nimport \"errors\"\n\n// ErrMissingFile is returned when the file path is missing.\nvar ErrMissingFile = errors"
},
{
"path": "vendor/github.com/charmbracelet/x/ansi/kitty/options.go",
"chars": 8625,
"preview": "package kitty\n\nimport (\n\t\"encoding\"\n\t\"fmt\"\n\t\"strconv\"\n\t\"strings\"\n)\n\nvar (\n\t_ encoding.TextMarshaler = Options{}\n\t_ enc"
},
{
"path": "vendor/github.com/charmbracelet/x/ansi/kitty.go",
"chars": 2634,
"preview": "package ansi\n\nimport \"strconv\"\n\n// Kitty keyboard protocol progressive enhancement flags.\n// See: https://sw.kovidgoyal."
},
{
"path": "vendor/github.com/charmbracelet/x/ansi/method.go",
"chars": 8177,
"preview": "package ansi\n\n// Method is a type that represents the how the renderer should calculate the\n// display width of cells.\nt"
},
{
"path": "vendor/github.com/charmbracelet/x/ansi/mode.go",
"chars": 21586,
"preview": "package ansi\n\nimport (\n\t\"strconv\"\n\t\"strings\"\n)\n\n// ModeSetting represents a mode setting.\ntype ModeSetting byte\n\n// Mode"
},
{
"path": "vendor/github.com/charmbracelet/x/ansi/modes.go",
"chars": 1904,
"preview": "package ansi\n\n// Modes represents the terminal modes that can be set or reset. By default,\n// all modes are [ModeNotReco"
},
{
"path": "vendor/github.com/charmbracelet/x/ansi/mouse.go",
"chars": 4363,
"preview": "package ansi\n\nimport (\n\t\"fmt\"\n)\n\n// MouseButton represents the button that was pressed during a mouse message.\ntype Mous"
},
{
"path": "vendor/github.com/charmbracelet/x/ansi/notification.go",
"chars": 279,
"preview": "package ansi\n\n// Notify sends a desktop notification using iTerm's OSC 9.\n//\n//\tOSC 9 ; Mc ST\n//\tOSC 9 ; Mc BEL\n//\n// Wh"
},
{
"path": "vendor/github.com/charmbracelet/x/ansi/parser/const.go",
"chars": 1392,
"preview": "package parser\n\n// Action is a DEC ANSI parser action.\ntype Action = byte\n\n// These are the actions that the parser can "
},
{
"path": "vendor/github.com/charmbracelet/x/ansi/parser/seq.go",
"chars": 3232,
"preview": "package parser\n\nimport \"math\"\n\n// Shift and masks for sequence parameters and intermediates.\nconst (\n\tPrefixShift = 8"
},
{
"path": "vendor/github.com/charmbracelet/x/ansi/parser/transition_table.go",
"chars": 12782,
"preview": "package parser\n\n// Table values are generated like this:\n//\n//\tindex: currentState << IndexStateShift | charCode\n//\tval"
},
{
"path": "vendor/github.com/charmbracelet/x/ansi/parser.go",
"chars": 10844,
"preview": "package ansi\n\nimport (\n\t\"unicode/utf8\"\n\t\"unsafe\"\n\n\t\"github.com/charmbracelet/x/ansi/parser\"\n)\n\n// Parser represents a DE"
},
{
"path": "vendor/github.com/charmbracelet/x/ansi/parser_decode.go",
"chars": 15678,
"preview": "package ansi\n\nimport (\n\t\"unicode/utf8\"\n\n\t\"github.com/charmbracelet/x/ansi/parser\"\n\t\"github.com/mattn/go-runewidth\"\n\t\"git"
},
{
"path": "vendor/github.com/charmbracelet/x/ansi/parser_handler.go",
"chars": 2135,
"preview": "package ansi\n\nimport \"unsafe\"\n\n// Params represents a list of packed parameters.\ntype Params []Param\n\n// Param returns t"
},
{
"path": "vendor/github.com/charmbracelet/x/ansi/parser_sync.go",
"chars": 528,
"preview": "package ansi\n\nimport (\n\t\"sync\"\n\n\t\"github.com/charmbracelet/x/ansi/parser\"\n)\n\nvar parserPool = sync.Pool{\n\tNew: func() an"
},
{
"path": "vendor/github.com/charmbracelet/x/ansi/passthrough.go",
"chars": 1880,
"preview": "package ansi\n\nimport (\n\t\"bytes\"\n)\n\n// ScreenPassthrough wraps the given ANSI sequence in a DCS passthrough\n// sequence t"
},
{
"path": "vendor/github.com/charmbracelet/x/ansi/paste.go",
"chars": 250,
"preview": "package ansi\n\n// BracketedPasteStart is the control sequence to enable bracketed paste mode.\nconst BracketedPasteStart ="
},
{
"path": "vendor/github.com/charmbracelet/x/ansi/reset.go",
"chars": 225,
"preview": "package ansi\n\n// ResetInitialState (RIS) resets the terminal to its initial state.\n//\n//\tESC c\n//\n// See: https://vt100."
},
{
"path": "vendor/github.com/charmbracelet/x/ansi/screen.go",
"chars": 9331,
"preview": "package ansi\n\nimport (\n\t\"strconv\"\n\t\"strings\"\n)\n\n// EraseDisplay (ED) clears the display or parts of the display. A scree"
},
{
"path": "vendor/github.com/charmbracelet/x/ansi/sgr.go",
"chars": 2950,
"preview": "package ansi\n\nimport \"strconv\"\n\n// Select Graphic Rendition (SGR) is a command that sets display attributes.\n//\n// Defau"
},
{
"path": "vendor/github.com/charmbracelet/x/ansi/status.go",
"chars": 3748,
"preview": "package ansi\n\nimport (\n\t\"strconv\"\n\t\"strings\"\n)\n\n// StatusReport represents a terminal status report.\ntype StatusReport i"
},
{
"path": "vendor/github.com/charmbracelet/x/ansi/style.go",
"chars": 21185,
"preview": "package ansi\n\nimport (\n\t\"image/color\"\n\t\"strconv\"\n\t\"strings\"\n)\n\n// ResetStyle is a SGR (Select Graphic Rendition) style s"
},
{
"path": "vendor/github.com/charmbracelet/x/ansi/termcap.go",
"chars": 895,
"preview": "package ansi\n\nimport (\n\t\"encoding/hex\"\n\t\"strings\"\n)\n\n// RequestTermcap (XTGETTCAP) requests Termcap/Terminfo strings.\n//"
},
{
"path": "vendor/github.com/charmbracelet/x/ansi/title.go",
"chars": 877,
"preview": "package ansi\n\n// SetIconNameWindowTitle returns a sequence for setting the icon name and\n// window title.\n//\n//\tOSC 0 ; "
},
{
"path": "vendor/github.com/charmbracelet/x/ansi/truncate.go",
"chars": 7165,
"preview": "package ansi\n\nimport (\n\t\"bytes\"\n\n\t\"github.com/charmbracelet/x/ansi/parser\"\n\t\"github.com/mattn/go-runewidth\"\n\t\"github.com"
},
{
"path": "vendor/github.com/charmbracelet/x/ansi/util.go",
"chars": 2345,
"preview": "package ansi\n\nimport (\n\t\"fmt\"\n\t\"image/color\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"github.com/lucasb-eyer/go-colorful\"\n)\n\n// colorToH"
},
{
"path": "vendor/github.com/charmbracelet/x/ansi/width.go",
"chars": 2873,
"preview": "package ansi\n\nimport (\n\t\"bytes\"\n\n\t\"github.com/charmbracelet/x/ansi/parser\"\n\t\"github.com/mattn/go-runewidth\"\n\t\"github.com"
},
{
"path": "vendor/github.com/charmbracelet/x/ansi/winop.go",
"chars": 1363,
"preview": "package ansi\n\nimport (\n\t\"strconv\"\n\t\"strings\"\n)\n\nconst (\n\t// ResizeWindowWinOp is a window operation that resizes the ter"
},
{
"path": "vendor/github.com/charmbracelet/x/ansi/wrap.go",
"chars": 10737,
"preview": "package ansi\n\nimport (\n\t\"bytes\"\n\t\"unicode\"\n\t\"unicode/utf8\"\n\n\t\"github.com/charmbracelet/x/ansi/parser\"\n\t\"github.com/mattn"
},
{
"path": "vendor/github.com/charmbracelet/x/ansi/xterm.go",
"chars": 4378,
"preview": "package ansi\n\nimport \"strconv\"\n\n// KeyModifierOptions (XTMODKEYS) sets/resets xterm key modifier options.\n//\n// Default "
},
{
"path": "vendor/github.com/charmbracelet/x/term/LICENSE",
"chars": 1076,
"preview": "MIT License\n\nCopyright (c) 2023 Charmbracelet, Inc.\n\nPermission is hereby granted, free of charge, to any person obtaini"
},
{
"path": "vendor/github.com/charmbracelet/x/term/term.go",
"chars": 1438,
"preview": "package term\n\n// State contains platform-specific state of a terminal.\ntype State struct {\n\tstate\n}\n\n// IsTerminal retur"
},
{
"path": "vendor/github.com/charmbracelet/x/term/term_other.go",
"chars": 1246,
"preview": "//go:build !aix && !darwin && !dragonfly && !freebsd && !linux && !netbsd && !openbsd && !zos && !windows && !solaris &&"
},
{
"path": "vendor/github.com/charmbracelet/x/term/term_unix.go",
"chars": 2562,
"preview": "//go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris || zos\n// +build aix darwin dr"
},
{
"path": "vendor/github.com/charmbracelet/x/term/term_unix_bsd.go",
"chars": 240,
"preview": "//go:build darwin || dragonfly || freebsd || netbsd || openbsd\n// +build darwin dragonfly freebsd netbsd openbsd\n\npackag"
},
{
"path": "vendor/github.com/charmbracelet/x/term/term_unix_other.go",
"chars": 197,
"preview": "//go:build aix || linux || solaris || zos\n// +build aix linux solaris zos\n\npackage term\n\nimport \"golang.org/x/sys/unix\"\n"
},
{
"path": "vendor/github.com/charmbracelet/x/term/term_windows.go",
"chars": 2254,
"preview": "//go:build windows\n// +build windows\n\npackage term\n\nimport (\n\t\"os\"\n\n\t\"golang.org/x/sys/windows\"\n)\n\ntype state struct {\n\t"
},
{
"path": "vendor/github.com/charmbracelet/x/term/terminal.go",
"chars": 192,
"preview": "package term\n\nimport (\n\t\"io\"\n)\n\n// File represents a file that has a file descriptor and can be read from,\n// written to"
},
{
"path": "vendor/github.com/charmbracelet/x/term/util.go",
"chars": 960,
"preview": "package term\n\nimport (\n\t\"io\"\n\t\"runtime\"\n)\n\n// readPasswordLine reads from reader until it finds \\n or io.EOF.\n// The sli"
},
{
"path": "vendor/github.com/erikgeiser/coninput/.golangci.yml",
"chars": 415,
"preview": "linters:\n enable-all: true\n disable:\n - golint\n - interfacer\n - scopelint\n - maligned\n - rowserrcheck\n "
},
{
"path": "vendor/github.com/erikgeiser/coninput/LICENSE",
"chars": 1064,
"preview": "MIT License\n\nCopyright (c) 2021 Erik G.\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof"
},
{
"path": "vendor/github.com/erikgeiser/coninput/README.md",
"chars": 67,
"preview": "# coninput\nGo library for input handling using Windows Console API\n"
},
{
"path": "vendor/github.com/erikgeiser/coninput/keycodes.go",
"chars": 9245,
"preview": "package coninput\n\n// VirtualKeyCode holds a virtual key code (see\n// https://docs.microsoft.com/en-us/windows/win32/inpu"
},
{
"path": "vendor/github.com/erikgeiser/coninput/mode.go",
"chars": 2172,
"preview": "//go:build windows\n// +build windows\n\npackage coninput\n\nimport (\n\t\"strings\"\n\n\t\"golang.org/x/sys/windows\"\n)\n\n// AddInputM"
},
{
"path": "vendor/github.com/erikgeiser/coninput/read.go",
"chars": 5417,
"preview": "//go:build windows\n// +build windows\n\npackage coninput\n\nimport (\n\t\"fmt\"\n\t\"syscall\"\n\t\"unsafe\"\n\n\t\"golang.org/x/sys/windows"
}
]
// ... and 698 more files (download for full content)
About this extraction
This page contains the full source code of the Wraient/curd GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 898 files (19.6 MB), approximately 5.2M tokens, and a symbol index with 105600 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.