Showing preview only (2,369K chars total). Download the full file or copy to clipboard to get everything.
Repository: atuinsh/atuin
Branch: main
Commit: c636554333a0
Files: 418
Total size: 2.2 MB
Directory structure:
gitextract_6o_czke4/
├── .cargo/
│ └── audit.toml
├── .codespellrc
├── .dockerignore
├── .gitattributes
├── .github/
│ ├── DISCUSSION_TEMPLATE/
│ │ └── support.yml
│ ├── FUNDING.yml
│ ├── ISSUE_TEMPLATE/
│ │ └── bug.yaml
│ ├── dependabot.yml
│ ├── pull_request_template.md
│ └── workflows/
│ ├── codespell.yml
│ ├── docker.yaml
│ ├── installer.yml
│ ├── nix.yml
│ ├── release.yml
│ ├── rust.yml
│ ├── shellcheck.yml
│ └── update-nix-deps.yml
├── .gitignore
├── .mailmap
├── .rustfmt.toml
├── AGENTS.md
├── CHANGELOG.md
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── CONTRIBUTORS
├── Cargo.toml
├── Dockerfile
├── LICENSE
├── README.md
├── atuin.nix
├── atuin.plugin.zsh
├── cliff.toml
├── crates/
│ ├── atuin/
│ │ ├── Cargo.toml
│ │ ├── LICENSE
│ │ ├── build.rs
│ │ ├── src/
│ │ │ ├── command/
│ │ │ │ ├── client/
│ │ │ │ │ ├── account/
│ │ │ │ │ │ ├── change_password.rs
│ │ │ │ │ │ ├── delete.rs
│ │ │ │ │ │ ├── link.rs
│ │ │ │ │ │ ├── login.rs
│ │ │ │ │ │ ├── logout.rs
│ │ │ │ │ │ └── register.rs
│ │ │ │ │ ├── account.rs
│ │ │ │ │ ├── daemon.rs
│ │ │ │ │ ├── default_config.rs
│ │ │ │ │ ├── doctor.rs
│ │ │ │ │ ├── dotfiles/
│ │ │ │ │ │ ├── alias.rs
│ │ │ │ │ │ └── var.rs
│ │ │ │ │ ├── dotfiles.rs
│ │ │ │ │ ├── history.rs
│ │ │ │ │ ├── import.rs
│ │ │ │ │ ├── info.rs
│ │ │ │ │ ├── init/
│ │ │ │ │ │ ├── bash.rs
│ │ │ │ │ │ ├── fish.rs
│ │ │ │ │ │ ├── powershell.rs
│ │ │ │ │ │ ├── xonsh.rs
│ │ │ │ │ │ └── zsh.rs
│ │ │ │ │ ├── init.rs
│ │ │ │ │ ├── kv.rs
│ │ │ │ │ ├── scripts.rs
│ │ │ │ │ ├── search/
│ │ │ │ │ │ ├── cursor.rs
│ │ │ │ │ │ ├── duration.rs
│ │ │ │ │ │ ├── engines/
│ │ │ │ │ │ │ ├── daemon.rs
│ │ │ │ │ │ │ ├── db.rs
│ │ │ │ │ │ │ └── skim.rs
│ │ │ │ │ │ ├── engines.rs
│ │ │ │ │ │ ├── history_list.rs
│ │ │ │ │ │ ├── inspector.rs
│ │ │ │ │ │ ├── interactive.rs
│ │ │ │ │ │ └── keybindings/
│ │ │ │ │ │ ├── actions.rs
│ │ │ │ │ │ ├── conditions.rs
│ │ │ │ │ │ ├── defaults.rs
│ │ │ │ │ │ ├── key.rs
│ │ │ │ │ │ ├── keymap.rs
│ │ │ │ │ │ └── mod.rs
│ │ │ │ │ ├── search.rs
│ │ │ │ │ ├── setup.rs
│ │ │ │ │ ├── stats.rs
│ │ │ │ │ ├── store/
│ │ │ │ │ │ ├── pull.rs
│ │ │ │ │ │ ├── purge.rs
│ │ │ │ │ │ ├── push.rs
│ │ │ │ │ │ ├── rebuild.rs
│ │ │ │ │ │ ├── rekey.rs
│ │ │ │ │ │ └── verify.rs
│ │ │ │ │ ├── store.rs
│ │ │ │ │ ├── sync/
│ │ │ │ │ │ └── status.rs
│ │ │ │ │ ├── sync.rs
│ │ │ │ │ └── wrapped.rs
│ │ │ │ ├── client.rs
│ │ │ │ ├── contributors.rs
│ │ │ │ ├── external.rs
│ │ │ │ ├── gen_completions.rs
│ │ │ │ └── mod.rs
│ │ │ ├── main.rs
│ │ │ ├── shell/
│ │ │ │ ├── .gitattributes
│ │ │ │ ├── atuin.bash
│ │ │ │ ├── atuin.fish
│ │ │ │ ├── atuin.nu
│ │ │ │ ├── atuin.ps1
│ │ │ │ ├── atuin.xsh
│ │ │ │ └── atuin.zsh
│ │ │ └── sync.rs
│ │ └── tests/
│ │ ├── common/
│ │ │ └── mod.rs
│ │ ├── sync.rs
│ │ └── users.rs
│ ├── atuin-ai/
│ │ ├── Cargo.toml
│ │ ├── render-tests.sh
│ │ ├── replay-states.sh
│ │ ├── src/
│ │ │ ├── commands/
│ │ │ │ ├── debug_render.rs
│ │ │ │ ├── init.rs
│ │ │ │ └── inline.rs
│ │ │ ├── commands.rs
│ │ │ ├── lib.rs
│ │ │ └── tui/
│ │ │ ├── app.rs
│ │ │ ├── component.rs
│ │ │ ├── components.rs
│ │ │ ├── event.rs
│ │ │ ├── mod.rs
│ │ │ ├── popup.rs
│ │ │ ├── render.rs
│ │ │ ├── spinner.rs
│ │ │ ├── state.rs
│ │ │ ├── terminal.rs
│ │ │ └── view_model.rs
│ │ └── test-renders.json
│ ├── atuin-client/
│ │ ├── Cargo.toml
│ │ ├── config.toml
│ │ ├── meta-migrations/
│ │ │ └── 20260203030924_create_meta.sql
│ │ ├── migrations/
│ │ │ ├── 20210422143411_create_history.sql
│ │ │ ├── 20220505083406_create-events.sql
│ │ │ ├── 20220806155627_interactive_search_index.sql
│ │ │ ├── 20230315220114_drop-events.sql
│ │ │ ├── 20230319185725_deleted_at.sql
│ │ │ └── 20260224000100_history_author_intent.sql
│ │ ├── record-migrations/
│ │ │ ├── 20230531212437_create-records.sql
│ │ │ └── 20231127090831_create-store.sql
│ │ ├── src/
│ │ │ ├── api_client.rs
│ │ │ ├── auth.rs
│ │ │ ├── database.rs
│ │ │ ├── distro.rs
│ │ │ ├── encryption.rs
│ │ │ ├── history/
│ │ │ │ ├── builder.rs
│ │ │ │ └── store.rs
│ │ │ ├── history.rs
│ │ │ ├── hub.rs
│ │ │ ├── import/
│ │ │ │ ├── bash.rs
│ │ │ │ ├── fish.rs
│ │ │ │ ├── mod.rs
│ │ │ │ ├── nu.rs
│ │ │ │ ├── nu_histdb.rs
│ │ │ │ ├── powershell.rs
│ │ │ │ ├── replxx.rs
│ │ │ │ ├── resh.rs
│ │ │ │ ├── xonsh.rs
│ │ │ │ ├── xonsh_sqlite.rs
│ │ │ │ ├── zsh.rs
│ │ │ │ └── zsh_histdb.rs
│ │ │ ├── lib.rs
│ │ │ ├── login.rs
│ │ │ ├── logout.rs
│ │ │ ├── meta.rs
│ │ │ ├── ordering.rs
│ │ │ ├── plugin.rs
│ │ │ ├── record/
│ │ │ │ ├── encryption.rs
│ │ │ │ ├── mod.rs
│ │ │ │ ├── sqlite_store.rs
│ │ │ │ ├── store.rs
│ │ │ │ └── sync.rs
│ │ │ ├── register.rs
│ │ │ ├── secrets.rs
│ │ │ ├── settings/
│ │ │ │ ├── dotfiles.rs
│ │ │ │ ├── kv.rs
│ │ │ │ ├── meta.rs
│ │ │ │ ├── scripts.rs
│ │ │ │ └── watcher.rs
│ │ │ ├── settings.rs
│ │ │ ├── sync.rs
│ │ │ ├── theme.rs
│ │ │ └── utils.rs
│ │ └── tests/
│ │ └── data/
│ │ └── xonsh/
│ │ ├── xonsh-82eafbf5-9f43-489a-80d2-61c7dc6ef542.json
│ │ └── xonsh-de16af90-9148-4461-8df3-5b5659c6420d.json
│ ├── atuin-common/
│ │ ├── Cargo.toml
│ │ └── src/
│ │ ├── api.rs
│ │ ├── calendar.rs
│ │ ├── lib.rs
│ │ ├── record.rs
│ │ ├── shell.rs
│ │ ├── tls.rs
│ │ └── utils.rs
│ ├── atuin-daemon/
│ │ ├── Cargo.toml
│ │ ├── build.rs
│ │ ├── proto/
│ │ │ ├── control.proto
│ │ │ ├── history.proto
│ │ │ └── search.proto
│ │ ├── src/
│ │ │ ├── client.rs
│ │ │ ├── components/
│ │ │ │ ├── history.rs
│ │ │ │ ├── mod.rs
│ │ │ │ ├── search.rs
│ │ │ │ └── sync.rs
│ │ │ ├── control/
│ │ │ │ ├── mod.rs
│ │ │ │ └── service.rs
│ │ │ ├── daemon.rs
│ │ │ ├── events.rs
│ │ │ ├── history/
│ │ │ │ └── mod.rs
│ │ │ ├── lib.rs
│ │ │ ├── search/
│ │ │ │ ├── index.rs
│ │ │ │ └── mod.rs
│ │ │ └── server.rs
│ │ └── tests/
│ │ └── lifecycle.rs
│ ├── atuin-dotfiles/
│ │ ├── Cargo.toml
│ │ └── src/
│ │ ├── lib.rs
│ │ ├── shell/
│ │ │ ├── bash.rs
│ │ │ ├── fish.rs
│ │ │ ├── powershell.rs
│ │ │ ├── xonsh.rs
│ │ │ └── zsh.rs
│ │ ├── shell.rs
│ │ ├── store/
│ │ │ ├── alias.rs
│ │ │ └── var.rs
│ │ └── store.rs
│ ├── atuin-hex/
│ │ ├── Cargo.toml
│ │ └── src/
│ │ ├── lib.rs
│ │ └── osc133.rs
│ ├── atuin-history/
│ │ ├── Cargo.toml
│ │ ├── benches/
│ │ │ └── smart_sort.rs
│ │ └── src/
│ │ ├── lib.rs
│ │ ├── sort.rs
│ │ └── stats.rs
│ ├── atuin-kv/
│ │ ├── Cargo.toml
│ │ ├── migrations/
│ │ │ ├── 20250501160746_create_kv_db.down.sql
│ │ │ └── 20250501160746_create_kv_db.up.sql
│ │ └── src/
│ │ ├── database.rs
│ │ ├── lib.rs
│ │ ├── store/
│ │ │ ├── entry.rs
│ │ │ └── record.rs
│ │ └── store.rs
│ ├── atuin-nucleo/
│ │ ├── .gitignore
│ │ ├── CHANGELOG.md
│ │ ├── Cargo.toml
│ │ ├── LICENSE
│ │ ├── README.md
│ │ ├── bench/
│ │ │ ├── Cargo.toml
│ │ │ └── src/
│ │ │ └── main.rs
│ │ ├── matcher/
│ │ │ ├── Cargo.toml
│ │ │ ├── fuzz/
│ │ │ │ ├── .gitignore
│ │ │ │ ├── Cargo.toml
│ │ │ │ └── fuzz_targets/
│ │ │ │ └── fuzz_target_1.rs
│ │ │ ├── fuzz.sh
│ │ │ ├── generate_case_fold_table.sh
│ │ │ └── src/
│ │ │ ├── chars/
│ │ │ │ ├── case_fold.rs
│ │ │ │ └── normalize.rs
│ │ │ ├── chars.rs
│ │ │ ├── config.rs
│ │ │ ├── debug.rs
│ │ │ ├── exact.rs
│ │ │ ├── fuzzy_greedy.rs
│ │ │ ├── fuzzy_optimal.rs
│ │ │ ├── lib.rs
│ │ │ ├── matrix.rs
│ │ │ ├── pattern/
│ │ │ │ └── tests.rs
│ │ │ ├── pattern.rs
│ │ │ ├── prefilter.rs
│ │ │ ├── score.rs
│ │ │ ├── tests.rs
│ │ │ ├── utf32_str/
│ │ │ │ └── tests.rs
│ │ │ └── utf32_str.rs
│ │ ├── src/
│ │ │ ├── boxcar.rs
│ │ │ ├── lib.rs
│ │ │ ├── par_sort.rs
│ │ │ ├── pattern/
│ │ │ │ └── tests.rs
│ │ │ ├── pattern.rs
│ │ │ ├── tests.rs
│ │ │ └── worker.rs
│ │ ├── tarpaulin.toml
│ │ └── typos.toml
│ ├── atuin-scripts/
│ │ ├── Cargo.toml
│ │ ├── migrations/
│ │ │ ├── 20250326160051_create_scripts.down.sql
│ │ │ ├── 20250326160051_create_scripts.up.sql
│ │ │ ├── 20250402170430_unique_names.down.sql
│ │ │ └── 20250402170430_unique_names.up.sql
│ │ └── src/
│ │ ├── database.rs
│ │ ├── execution.rs
│ │ ├── lib.rs
│ │ ├── settings.rs
│ │ ├── store/
│ │ │ ├── record.rs
│ │ │ └── script.rs
│ │ └── store.rs
│ ├── atuin-server/
│ │ ├── Cargo.toml
│ │ ├── server.toml
│ │ └── src/
│ │ ├── bin/
│ │ │ └── main.rs
│ │ ├── handlers/
│ │ │ ├── health.rs
│ │ │ ├── history.rs
│ │ │ ├── mod.rs
│ │ │ ├── record.rs
│ │ │ ├── status.rs
│ │ │ ├── user.rs
│ │ │ └── v0/
│ │ │ ├── me.rs
│ │ │ ├── mod.rs
│ │ │ ├── record.rs
│ │ │ └── store.rs
│ │ ├── lib.rs
│ │ ├── metrics.rs
│ │ ├── router.rs
│ │ ├── settings.rs
│ │ └── utils.rs
│ ├── atuin-server-database/
│ │ ├── Cargo.toml
│ │ └── src/
│ │ ├── calendar.rs
│ │ ├── lib.rs
│ │ └── models.rs
│ ├── atuin-server-postgres/
│ │ ├── Cargo.toml
│ │ ├── build.rs
│ │ ├── migrations/
│ │ │ ├── 20210425153745_create_history.sql
│ │ │ ├── 20210425153757_create_users.sql
│ │ │ ├── 20210425153800_create_sessions.sql
│ │ │ ├── 20220419082412_add_count_trigger.sql
│ │ │ ├── 20220421073605_fix_count_trigger_delete.sql
│ │ │ ├── 20220421174016_larger-commands.sql
│ │ │ ├── 20220426172813_user-created-at.sql
│ │ │ ├── 20220505082442_create-events.sql
│ │ │ ├── 20220610074049_history-length.sql
│ │ │ ├── 20230315220537_drop-events.sql
│ │ │ ├── 20230315224203_create-deleted.sql
│ │ │ ├── 20230515221038_trigger-delete-only.sql
│ │ │ ├── 20230623070418_records.sql
│ │ │ ├── 20231202170508_create-store.sql
│ │ │ ├── 20231203124112_create-store-idx.sql
│ │ │ ├── 20240108124837_drop-some-defaults.sql
│ │ │ ├── 20240614104159_idx-cache.sql
│ │ │ ├── 20240621110731_user-verified.sql
│ │ │ ├── 20240702094825_idx_cache_index.sql
│ │ │ └── 20260127000000_remove-email-verification.sql
│ │ └── src/
│ │ ├── lib.rs
│ │ └── wrappers.rs
│ └── atuin-server-sqlite/
│ ├── Cargo.toml
│ ├── build.rs
│ ├── migrations/
│ │ ├── 20231203124112_create-store.sql
│ │ ├── 20240108124830_create-history.sql
│ │ ├── 20240108124831_create-sessions.sql
│ │ ├── 20240621110730_create-users.sql
│ │ ├── 20240621110731_create-user-verification-token.sql
│ │ ├── 20240702094825_create-store-idx-cache.sql
│ │ └── 20260127000000_remove-email-verification.sql
│ └── src/
│ ├── lib.rs
│ └── wrappers.rs
├── default.nix
├── deny.toml
├── depot.json
├── dist-workspace.toml
├── docker-compose.yml
├── docs/
│ ├── .gitignore
│ ├── docs/
│ │ ├── ai/
│ │ │ ├── introduction.md
│ │ │ └── settings.md
│ │ ├── configuration/
│ │ │ ├── advanced-key-binding.md
│ │ │ ├── config.md
│ │ │ └── key-binding.md
│ │ ├── faq.md
│ │ ├── guide/
│ │ │ ├── advanced-usage.md
│ │ │ ├── basic-usage.md
│ │ │ ├── delete-history.md
│ │ │ ├── dotfiles.md
│ │ │ ├── getting-started.md
│ │ │ ├── import.md
│ │ │ ├── installation.md
│ │ │ ├── shell-integration.md
│ │ │ ├── sync.md
│ │ │ └── theming.md
│ │ ├── index.md
│ │ ├── integrations.md
│ │ ├── known-issues.md
│ │ ├── reference/
│ │ │ ├── daemon.md
│ │ │ ├── doctor.md
│ │ │ ├── gen-completions.md
│ │ │ ├── import.md
│ │ │ ├── info.md
│ │ │ ├── list.md
│ │ │ ├── prune.md
│ │ │ ├── search.md
│ │ │ ├── stats.md
│ │ │ └── sync.md
│ │ ├── self-hosting/
│ │ │ ├── docker.md
│ │ │ ├── kubernetes.md
│ │ │ ├── server-setup.md
│ │ │ ├── systemd.md
│ │ │ └── usage.md
│ │ ├── sync-v2.md
│ │ └── uninstall.md
│ ├── mkdocs.yml
│ └── pyproject.toml
├── docs-i18n/
│ ├── .gitignore
│ ├── ru/
│ │ ├── config_ru.md
│ │ ├── import_ru.md
│ │ ├── key-binding_ru.md
│ │ ├── list_ru.md
│ │ ├── search_ru.md
│ │ ├── server_ru.md
│ │ ├── shell-completions_ru.md
│ │ ├── stats_ru.md
│ │ └── sync_ru.md
│ └── zh-CN/
│ ├── README.md
│ ├── config.md
│ ├── docker.md
│ ├── import.md
│ ├── k8s.md
│ ├── key-binding.md
│ ├── list.md
│ ├── search.md
│ ├── server.md
│ ├── shell-completions.md
│ ├── stats.md
│ └── sync.md
├── flake.nix
├── install.sh
├── k8s/
│ ├── atuin.yaml
│ ├── namespaces.yaml
│ └── secrets.yaml
├── rust-toolchain.toml
├── scripts/
│ └── span-table.ts
└── systemd/
├── atuin-server.service
└── atuin-server.sysusers
================================================
FILE CONTENTS
================================================
================================================
FILE: .cargo/audit.toml
================================================
[advisories]
ignore = [
# This is a vuln on RSA. RSA is in our lockfile, but not in cargo-tree.
# It is a issue with sqlx/cargo, and does not affect Atuin.
# See:
# - https://github.com/launchbadge/sqlx/issues/3211
# - https://github.com/rust-lang/cargo/issues/10801
"RUSTSEC-2023-0071"
]
================================================
FILE: .codespellrc
================================================
[codespell]
# Ref: https://github.com/codespell-project/codespell#using-a-config-file
skip = .git*,*.lock,.codespellrc,CODE_OF_CONDUCT.md,CONTRIBUTORS
check-hidden = true
# ignore-regex =
ignore-words-list = crate,ratatui,inbetween,iterm,fo,brunch
================================================
FILE: .dockerignore
================================================
./target
Dockerfile
================================================
FILE: .gitattributes
================================================
*.sh eol=lf
*.nix eol=lf
*.zsh eol=lf
*.sql eol=lf
================================================
FILE: .github/DISCUSSION_TEMPLATE/support.yml
================================================
body:
- type: input
attributes:
label: Operating System
description: What operating system are you using?
placeholder: "Example: macOS Big Sur"
validations:
required: true
- type: input
attributes:
label: Shell
description: What shell are you using?
placeholder: "Example: zsh 5.8.1"
validations:
required: true
- type: dropdown
attributes:
label: Version
description: What version of atuin are you running?
multiple: false
options: # how often will I forget to update this? a lot.
- v17.0.0 (Default)
- v16.0.0
- v15.0.0
- v14.0.1
- v14.0.0
- v13.0.1
- v13.0.0
- v12.0.0
- v11.0.0
- v0.10.0
- v0.9.1
- v0.9.0
- v0.8.1
- v0.8.0
- v0.7.2
- v0.7.1
- v0.7.0
- v0.6.4
- v0.6.3
default: 0
validations:
required: true
- type: checkboxes
attributes:
label: Self hosted
description: Are you self hosting atuin server?
options:
- label: I am self hosting atuin server
- type: checkboxes
attributes:
label: Search the issues
description: Did you search the issues and discussions for your problem?
options:
- label: I checked that someone hasn't already asked about the same issue
required: true
- type: textarea
attributes:
label: Behaviour
description: "Please describe the issue - what you expected to happen, what actually happened"
- type: textarea
attributes:
label: Logs
description: "If possible, please include logs from atuin, especially if you self host the server - ATUIN_LOG=debug"
- type: textarea
attributes:
label: Extra information
description: "Anything else you'd like to add?"
- type: checkboxes
attributes:
label: Code of Conduct
description: The Code of Conduct helps create a safe space for everyone. We require
that everyone agrees to it.
options:
- label: I agree to follow this project's [Code of Conduct](https://github.com/atuinsh/atuin/blob/main/CODE_OF_CONDUCT.md)
required: true
================================================
FILE: .github/FUNDING.yml
================================================
# These are supported funding model platforms
github: [atuinsh]
patreon: # Replace with a single Patreon username
open_collective: # Replace with a single Open Collective username
ko_fi: # Replace with a single Ko-fi username
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
liberapay: # Replace with a single Liberapay username
issuehunt: # Replace with a single IssueHunt username
otechie: # Replace with a single Otechie username
lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry
custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
================================================
FILE: .github/ISSUE_TEMPLATE/bug.yaml
================================================
name: Bug Report
description: File a bug report
title: "[Bug]: "
labels: ["bug", "triage"]
body:
- type: markdown
attributes:
value: |
Thanks for taking the time to fill out this bug report!
- type: textarea
id: what-expected
attributes:
label: What did you expect to happen?
placeholder: Tell us what you expected to see!
validations:
required: true
- type: textarea
id: what-happened
attributes:
label: What happened?
placeholder: Tell us what you see!
validations:
required: true
- type: textarea
id: doctor
validations:
required: true
attributes:
label: Atuin doctor output
description: Please run 'atuin doctor' and share the output. If it fails to run, share any errors. This requires Atuin >=v18.1.0
render: yaml
- type: checkboxes
id: terms
attributes:
label: Code of Conduct
description: By submitting this issue, you agree to follow our [Code of Conduct](https://github.com/atuinsh/atuin/blob/main/CODE_OF_CONDUCT.md)
options:
- label: I agree to follow this project's Code of Conduct
required: true
================================================
FILE: .github/dependabot.yml
================================================
# To get started with Dependabot version updates, you'll need to specify which
# package ecosystems to update and where the package manifests are located.
# Please see the documentation for all configuration options:
# https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
version: 2
updates:
- package-ecosystem: "cargo" # See documentation for possible values
directory: "/" # Location of package manifests
schedule:
interval: "weekly"
- package-ecosystem: "docker" # See documentation for possible values
directory: "/" # Location of package manifests
schedule:
interval: "weekly"
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly"
================================================
FILE: .github/pull_request_template.md
================================================
<!-- Thank you for making a PR! Bug fixes are always welcome, but if you're adding a new feature or changing an existing one, we'd really appreciate if you open an issue, post on the forum, or drop in on Discord -->
## Checks
- [ ] I am happy for maintainers to push small adjustments to this PR, to speed up the review cycle
- [ ] I have checked that there are no existing pull requests for the same thing
================================================
FILE: .github/workflows/codespell.yml
================================================
# Codespell configuration is within .codespellrc
---
name: Codespell
on:
push:
branches: [main]
pull_request:
branches: [main]
permissions:
contents: read
jobs:
codespell:
name: Check for spelling errors
runs-on: depot-ubuntu-24.04
steps:
- name: Checkout
uses: actions/checkout@v6
- name: Codespell
uses: codespell-project/actions-codespell@v2
with:
# This is regenerated from commit history
# we cannot rewrite commit history, and I'd rather not correct it
# every time
exclude_file: CHANGELOG.md
================================================
FILE: .github/workflows/docker.yaml
================================================
name: build-docker
on:
push:
branches: [main]
jobs:
publish:
concurrency:
group: ${{ github.ref }}-docker
cancel-in-progress: true
permissions:
packages: write
contents: read
id-token: write
runs-on: depot-ubuntu-24.04
steps:
- uses: actions/checkout@v6
- name: Get Repo Owner
id: get_repo_owner
run: echo "REPO_OWNER=$(echo ${{ github.repository_owner }} | tr '[:upper:]' '[:lower:]')" > $GITHUB_ENV
- uses: depot/setup-action@v1
- name: Login to container Registry
uses: docker/login-action@v3
with:
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}
registry: ghcr.io
- name: Get short sha
id: shortsha
run: echo "short_sha=$(git rev-parse --short HEAD)" >> $GITHUB_OUTPUT
- name: Build and push
uses: depot/build-push-action@v1
with:
push: true
platforms: linux/amd64,linux/arm64
file: ./Dockerfile
context: .
provenance: false
build-args: |
Version=dev
GitCommit=${{ steps.shortsha.outputs.short_sha }}
tags: |
ghcr.io/${{ env.REPO_OWNER }}/atuin:${{ steps.shortsha.outputs.short_sha }}
================================================
FILE: .github/workflows/installer.yml
================================================
name: Install
on:
push:
branches: [main]
pull_request:
paths: .github/workflows/installer.yml
env:
CARGO_TERM_COLOR: always
jobs:
install:
strategy:
matrix:
os: [depot-ubuntu-24.04, macos-14]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v6
- name: Install zsh for ubuntu
if: matrix.os == 'depot-ubuntu-24.04'
run: |
sudo apt install zsh
- name: Test install script on bash
run: |
/bin/bash -c "$(curl --proto '=https' --tlsv1.2 -sSf https://setup.atuin.sh)"
[ -d "$HOME/.atuin" ] && source $HOME/.atuin/bin/env
atuin --help
- name: Test install script on zsh
shell: zsh {0}
run: |
/bin/bash -c "$(curl --proto '=https' --tlsv1.2 -sSf https://setup.atuin.sh)"
[ -d "$HOME/.atuin" ] && source $HOME/.atuin/bin/env
atuin --help
================================================
FILE: .github/workflows/nix.yml
================================================
# Verify the Nix build is working
# Failures will usually occur due to an out of date Rust version
# That can be updated to the latest version in nixpkgs-unstable with `nix flake update`
name: Nix
on:
push:
branches: [ main ]
paths-ignore:
- 'ui/**'
pull_request:
branches: [ main ]
paths-ignore:
- 'ui/**'
jobs:
check:
runs-on: depot-ubuntu-24.04
steps:
- uses: actions/checkout@v6
- uses: cachix/install-nix-action@v31
- name: Run nix flake check
run: nix flake check --print-build-logs
build-test:
runs-on: depot-ubuntu-24.04
steps:
- uses: actions/checkout@v6
- uses: cachix/install-nix-action@v31
- name: Run nix build
run: nix build --print-build-logs
================================================
FILE: .github/workflows/release.yml
================================================
# This file was autogenerated by dist: https://axodotdev.github.io/cargo-dist
#
# Copyright 2022-2024, axodotdev
# SPDX-License-Identifier: MIT or Apache-2.0
#
# CI that:
#
# * checks for a Git Tag that looks like a release
# * builds artifacts with dist (archives, installers, hashes)
# * uploads those artifacts to temporary workflow zip
# * on success, uploads the artifacts to a GitHub Release
#
# Note that the GitHub Release will be created with a generated
# title/body based on your changelogs.
name: Release
permissions:
"contents": "write"
# This task will run whenever you push a git tag that looks like a version
# like "1.0.0", "v0.1.0-prerelease.1", "my-app/0.1.0", "releases/v1.0.0", etc.
# Various formats will be parsed into a VERSION and an optional PACKAGE_NAME, where
# PACKAGE_NAME must be the name of a Cargo package in your workspace, and VERSION
# must be a Cargo-style SemVer Version (must have at least major.minor.patch).
#
# If PACKAGE_NAME is specified, then the announcement will be for that
# package (erroring out if it doesn't have the given version or isn't dist-able).
#
# If PACKAGE_NAME isn't specified, then the announcement will be for all
# (dist-able) packages in the workspace with that version (this mode is
# intended for workspaces with only one dist-able package, or with all dist-able
# packages versioned/released in lockstep).
#
# If you push multiple tags at once, separate instances of this workflow will
# spin up, creating an independent announcement for each one. However, GitHub
# will hard limit this to 3 tags per commit, as it will assume more tags is a
# mistake.
#
# If there's a prerelease-style suffix to the version, then the release(s)
# will be marked as a prerelease.
on:
pull_request:
push:
tags:
- '**[0-9]+.[0-9]+.[0-9]+*'
jobs:
# Run 'dist plan' (or host) to determine what tasks we need to do
plan:
runs-on: "ubuntu-22.04"
outputs:
val: ${{ steps.plan.outputs.manifest }}
tag: ${{ !github.event.pull_request && github.ref_name || '' }}
tag-flag: ${{ !github.event.pull_request && format('--tag={0}', github.ref_name) || '' }}
publishing: ${{ !github.event.pull_request }}
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
steps:
- uses: actions/checkout@v6
with:
persist-credentials: false
submodules: recursive
- name: Install dist
# we specify bash to get pipefail; it guards against the `curl` command
# failing. otherwise `sh` won't catch that `curl` returned non-0
shell: bash
run: "curl --proto '=https' --tlsv1.2 -LsSf https://github.com/axodotdev/cargo-dist/releases/download/v0.31.0/cargo-dist-installer.sh | sh"
- name: Cache dist
uses: actions/upload-artifact@v6
with:
name: cargo-dist-cache
path: ~/.cargo/bin/dist
# sure would be cool if github gave us proper conditionals...
# so here's a doubly-nested ternary-via-truthiness to try to provide the best possible
# functionality based on whether this is a pull_request, and whether it's from a fork.
# (PRs run on the *source* but secrets are usually on the *target* -- that's *good*
# but also really annoying to build CI around when it needs secrets to work right.)
- id: plan
run: |
dist ${{ (!github.event.pull_request && format('host --steps=create --tag={0}', github.ref_name)) || 'plan' }} --output-format=json > plan-dist-manifest.json
echo "dist ran successfully"
cat plan-dist-manifest.json
echo "manifest=$(jq -c "." plan-dist-manifest.json)" >> "$GITHUB_OUTPUT"
- name: "Upload dist-manifest.json"
uses: actions/upload-artifact@v6
with:
name: artifacts-plan-dist-manifest
path: plan-dist-manifest.json
# Build and packages all the platform-specific things
build-local-artifacts:
name: build-local-artifacts (${{ join(matrix.targets, ', ') }})
# Let the initial task tell us to not run (currently very blunt)
needs:
- plan
if: ${{ fromJson(needs.plan.outputs.val).ci.github.artifacts_matrix.include != null && (needs.plan.outputs.publishing == 'true' || fromJson(needs.plan.outputs.val).ci.github.pr_run_mode == 'upload') }}
strategy:
fail-fast: false
# Target platforms/runners are computed by dist in create-release.
# Each member of the matrix has the following arguments:
#
# - runner: the github runner
# - dist-args: cli flags to pass to dist
# - install-dist: expression to run to install dist on the runner
#
# Typically there will be:
# - 1 "global" task that builds universal installers
# - N "local" tasks that build each platform's binaries and platform-specific installers
matrix: ${{ fromJson(needs.plan.outputs.val).ci.github.artifacts_matrix }}
runs-on: ${{ matrix.runner }}
container: ${{ matrix.container && matrix.container.image || null }}
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
BUILD_MANIFEST_NAME: target/distrib/${{ join(matrix.targets, '-') }}-dist-manifest.json
permissions:
"attestations": "write"
"contents": "read"
"id-token": "write"
steps:
- name: enable windows longpaths
run: |
git config --global core.longpaths true
- uses: actions/checkout@v6
with:
persist-credentials: false
submodules: recursive
- name: Install Rust non-interactively if not already installed
if: ${{ matrix.container }}
run: |
if ! command -v cargo > /dev/null 2>&1; then
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y
echo "$HOME/.cargo/bin" >> $GITHUB_PATH
fi
- name: Install dist
run: ${{ matrix.install_dist.run }}
# Get the dist-manifest
- name: Fetch local artifacts
uses: actions/download-artifact@v7
with:
pattern: artifacts-*
path: target/distrib/
merge-multiple: true
- name: Install dependencies
run: |
${{ matrix.packages_install }}
- name: Build artifacts
run: |
# Actually do builds and make zips and whatnot
dist build ${{ needs.plan.outputs.tag-flag }} --print=linkage --output-format=json ${{ matrix.dist_args }} > dist-manifest.json
echo "dist ran successfully"
- name: Attest
uses: actions/attest-build-provenance@v3
with:
subject-path: "target/distrib/*${{ join(matrix.targets, ', ') }}*"
- id: cargo-dist
name: Post-build
# We force bash here just because github makes it really hard to get values up
# to "real" actions without writing to env-vars, and writing to env-vars has
# inconsistent syntax between shell and powershell.
shell: bash
run: |
# Parse out what we just built and upload it to scratch storage
echo "paths<<EOF" >> "$GITHUB_OUTPUT"
dist print-upload-files-from-manifest --manifest dist-manifest.json >> "$GITHUB_OUTPUT"
echo "EOF" >> "$GITHUB_OUTPUT"
cp dist-manifest.json "$BUILD_MANIFEST_NAME"
- name: "Upload artifacts"
uses: actions/upload-artifact@v6
with:
name: artifacts-build-local-${{ join(matrix.targets, '_') }}
path: |
${{ steps.cargo-dist.outputs.paths }}
${{ env.BUILD_MANIFEST_NAME }}
# Build and package all the platform-agnostic(ish) things
build-global-artifacts:
needs:
- plan
- build-local-artifacts
runs-on: "ubuntu-22.04"
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
BUILD_MANIFEST_NAME: target/distrib/global-dist-manifest.json
steps:
- uses: actions/checkout@v6
with:
persist-credentials: false
submodules: recursive
- name: Install cached dist
uses: actions/download-artifact@v7
with:
name: cargo-dist-cache
path: ~/.cargo/bin/
- run: chmod +x ~/.cargo/bin/dist
# Get all the local artifacts for the global tasks to use (for e.g. checksums)
- name: Fetch local artifacts
uses: actions/download-artifact@v7
with:
pattern: artifacts-*
path: target/distrib/
merge-multiple: true
- id: cargo-dist
shell: bash
run: |
dist build ${{ needs.plan.outputs.tag-flag }} --output-format=json "--artifacts=global" > dist-manifest.json
echo "dist ran successfully"
# Parse out what we just built and upload it to scratch storage
echo "paths<<EOF" >> "$GITHUB_OUTPUT"
jq --raw-output ".upload_files[]" dist-manifest.json >> "$GITHUB_OUTPUT"
echo "EOF" >> "$GITHUB_OUTPUT"
cp dist-manifest.json "$BUILD_MANIFEST_NAME"
- name: "Upload artifacts"
uses: actions/upload-artifact@v6
with:
name: artifacts-build-global
path: |
${{ steps.cargo-dist.outputs.paths }}
${{ env.BUILD_MANIFEST_NAME }}
# Determines if we should publish/announce
host:
needs:
- plan
- build-local-artifacts
- build-global-artifacts
# Only run if we're "publishing", and only if plan, local and global didn't fail (skipped is fine)
if: ${{ always() && needs.plan.result == 'success' && needs.plan.outputs.publishing == 'true' && (needs.build-global-artifacts.result == 'skipped' || needs.build-global-artifacts.result == 'success') && (needs.build-local-artifacts.result == 'skipped' || needs.build-local-artifacts.result == 'success') }}
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
runs-on: "ubuntu-22.04"
outputs:
val: ${{ steps.host.outputs.manifest }}
steps:
- uses: actions/checkout@v6
with:
persist-credentials: false
submodules: recursive
- name: Install cached dist
uses: actions/download-artifact@v7
with:
name: cargo-dist-cache
path: ~/.cargo/bin/
- run: chmod +x ~/.cargo/bin/dist
# Fetch artifacts from scratch-storage
- name: Fetch artifacts
uses: actions/download-artifact@v7
with:
pattern: artifacts-*
path: target/distrib/
merge-multiple: true
- id: host
shell: bash
run: |
dist host ${{ needs.plan.outputs.tag-flag }} --steps=upload --steps=release --output-format=json > dist-manifest.json
echo "artifacts uploaded and released successfully"
cat dist-manifest.json
echo "manifest=$(jq -c "." dist-manifest.json)" >> "$GITHUB_OUTPUT"
- name: "Upload dist-manifest.json"
uses: actions/upload-artifact@v6
with:
# Overwrite the previous copy
name: artifacts-dist-manifest
path: dist-manifest.json
# Create a GitHub Release while uploading all files to it
- name: "Download GitHub Artifacts"
uses: actions/download-artifact@v7
with:
pattern: artifacts-*
path: artifacts
merge-multiple: true
- name: Cleanup
run: |
# Remove the granular manifests
rm -f artifacts/*-dist-manifest.json
- name: Create GitHub Release
env:
PRERELEASE_FLAG: "${{ fromJson(steps.host.outputs.manifest).announcement_is_prerelease && '--prerelease' || '' }}"
ANNOUNCEMENT_TITLE: "${{ fromJson(steps.host.outputs.manifest).announcement_title }}"
ANNOUNCEMENT_BODY: "${{ fromJson(steps.host.outputs.manifest).announcement_github_body }}"
RELEASE_COMMIT: "${{ github.sha }}"
run: |
# Write and read notes from a file to avoid quoting breaking things
echo "$ANNOUNCEMENT_BODY" > $RUNNER_TEMP/notes.txt
gh release create "${{ needs.plan.outputs.tag }}" --target "$RELEASE_COMMIT" $PRERELEASE_FLAG --title "$ANNOUNCEMENT_TITLE" --notes-file "$RUNNER_TEMP/notes.txt" artifacts/*
announce:
needs:
- plan
- host
# use "always() && ..." to allow us to wait for all publish jobs while
# still allowing individual publish jobs to skip themselves (for prereleases).
# "host" however must run to completion, no skipping allowed!
if: ${{ always() && needs.host.result == 'success' }}
runs-on: "ubuntu-22.04"
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
steps:
- uses: actions/checkout@v6
with:
persist-credentials: false
submodules: recursive
================================================
FILE: .github/workflows/rust.yml
================================================
name: Rust
on:
push:
branches: [main]
paths-ignore:
- "ui/**"
pull_request:
branches: [main]
paths-ignore:
- "ui/**"
env:
CARGO_TERM_COLOR: always
jobs:
build:
strategy:
matrix:
os: [depot-ubuntu-24.04, macos-14, windows-latest]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v6
- name: Install rust
uses: dtolnay/rust-toolchain@master
with:
toolchain: 1.94.0
- uses: actions/cache@v5
with:
path: |
~/.cargo/registry
~/.cargo/git
target
key: ${{ runner.os }}-cargo-release-${{ hashFiles('**/Cargo.lock') }}
- name: Run cargo build common
run: cargo build -p atuin-common --locked --release
- name: Run cargo build client
run: cargo build -p atuin-client --locked --release
- name: Run cargo build server
run: cargo build -p atuin-server --locked --release
- name: Run cargo build main
run: cargo build --all --locked --release
cross-compile:
strategy:
matrix:
# There was an attempt to make cross-compiles also work on FreeBSD, but that failed with:
#
# warning: libelf.so.2, needed by <...>/libkvm.so, not found (try using -rpath or -rpath-link)
target: [x86_64-unknown-illumos]
runs-on: depot-ubuntu-24.04
steps:
- uses: actions/checkout@v6
- name: Install cross
uses: taiki-e/install-action@v2
with:
tool: cross
- uses: actions/cache@v5
with:
path: |
~/.cargo/registry
~/.cargo/git
target
key: ${{ matrix.target }}-cross-compile-${{ hashFiles('**/Cargo.lock') }}
- name: Run cross build common
run: cross build -p atuin-common --locked --target ${{ matrix.target }}
- name: Run cross build client
run: cross build -p atuin-client --locked --target ${{ matrix.target }}
- name: Run cross build server
run: cross build -p atuin-server --locked --target ${{ matrix.target }}
- name: Run cross build main
run: |
cross build --all --locked --target ${{ matrix.target }}
unit-test:
strategy:
matrix:
os: [depot-ubuntu-24.04, macos-14, windows-latest]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v6
- name: Install rust
uses: dtolnay/rust-toolchain@master
with:
toolchain: 1.94.0
- uses: taiki-e/install-action@v2
name: Install nextest
with:
tool: cargo-nextest
- uses: actions/cache@v5
with:
path: |
~/.cargo/registry
~/.cargo/git
target
key: ${{ runner.os }}-cargo-debug-${{ hashFiles('**/Cargo.lock') }}
- name: Run cargo test
run: cargo nextest run --lib --bins
check:
strategy:
matrix:
os: [depot-ubuntu-24.04, macos-14, windows-latest]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v6
- name: Install rust
uses: dtolnay/rust-toolchain@master
with:
toolchain: 1.94.0
- uses: actions/cache@v5
with:
path: |
~/.cargo/registry
~/.cargo/git
target
key: ${{ runner.os }}-cargo-debug-${{ hashFiles('**/Cargo.lock') }}
- name: Run cargo check (all features)
run: cargo check --all-features --workspace
- name: Run cargo check (no features)
run: cargo check --no-default-features --workspace
- name: Run cargo check (sync)
run: cargo check --no-default-features --features sync --workspace
- name: Run cargo check (server)
run: cargo check -p atuin-server
- name: Run cargo check (client only)
run: cargo check --no-default-features --features client --workspace
integration-test:
runs-on: depot-ubuntu-24.04
services:
postgres:
image: postgres
env:
POSTGRES_USER: atuin
POSTGRES_PASSWORD: pass
POSTGRES_DB: atuin
ports:
- 5432:5432
steps:
- uses: actions/checkout@v6
- name: Install rust
uses: dtolnay/rust-toolchain@master
with:
toolchain: 1.94.0
- uses: taiki-e/install-action@v2
name: Install nextest
with:
tool: cargo-nextest
- uses: actions/cache@v5
with:
path: |
~/.cargo/registry
~/.cargo/git
target
key: ${{ runner.os }}-cargo-debug-${{ hashFiles('**/Cargo.lock') }}
- name: Run cargo test
run: cargo nextest run --test '*'
env:
ATUIN_DB_URI: postgres://atuin:pass@localhost:5432/atuin
clippy:
runs-on: depot-ubuntu-24.04
steps:
- uses: actions/checkout@v6
- name: Install latest rust
uses: dtolnay/rust-toolchain@master
with:
toolchain: 1.94.0
components: clippy
- uses: actions/cache@v5
with:
path: |
~/.cargo/registry
~/.cargo/git
target
key: ${{ runner.os }}-cargo-debug-${{ hashFiles('**/Cargo.lock') }}
- name: Run clippy
run: cargo clippy -- -D warnings -D clippy::redundant_clone
format:
runs-on: depot-ubuntu-24.04
steps:
- uses: actions/checkout@v6
- name: Install latest rust
uses: dtolnay/rust-toolchain@master
with:
toolchain: 1.94.0
components: rustfmt
- name: Format
run: cargo fmt -- --check
================================================
FILE: .github/workflows/shellcheck.yml
================================================
name: Shellcheck
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
jobs:
shellcheck:
runs-on: depot-ubuntu-24.04
steps:
- uses: actions/checkout@v6
- name: Run shellcheck
uses: ludeeus/action-shellcheck@master
env:
SHELLCHECK_OPTS: "-e SC2148"
================================================
FILE: .github/workflows/update-nix-deps.yml
================================================
name: Update Nix Deps
on:
workflow_dispatch: # allows manual triggering
schedule:
- cron: '0 0 1 * *' # runs monthly on the first day of the month at 00:00
jobs:
lockfile:
runs-on: depot-ubuntu-24.04
if: github.repository == 'atuinsh/atuin'
steps:
- name: Checkout repository
uses: actions/checkout@v6
- name: Install Nix
uses: DeterminateSystems/nix-installer-action@main
- name: Update flake.lock
uses: DeterminateSystems/update-flake-lock@main
with:
pr-title: "chore(deps): update flake.lock"
pr-labels: |
dependencies
================================================
FILE: .gitignore
================================================
.DS_Store
/target
*/target
.env
.idea/
.vscode/
result
publish.sh
.envrc
.planning/
ui/backend/target
ui/backend/gen
sqlite-server.db*
================================================
FILE: .mailmap
================================================
networkException <git@nwex.de> <github@nwex.de>
Violet Shreve <github@shreve.io> <jacob@shreve.io>
Chris Rose <offline@offby1.net> <offbyone@github.com>
Conrad Ludgate <conradludgate@gmail.com> <conrad.ludgate@truelayer.com>
Cristian Le <github@lecris.me> <cristian.le@mpsd.mpg.de>
Dennis Trautwein <git@dtrautwein.eu> <dennis.trautwein@posteo.de>
Ellie Huxtable <ellie@atuin.sh> <e@elm.sh>
Ellie Huxtable <ellie@atuin.sh> <ellie@elliehuxtable.com>
Frank Hamand <frankhamand@gmail.com> <frank.hamand@coinbase.com>
Jakob Schrettenbrunner <dev@schrej.net> <jakob.schrettenbrunner@telekom.de>
Nemo157 <git@nemo157.com> <github@nemo157.com>
Richard de Boer <git@tubul.net> <github@tubul.net>
Sandro <sandro.jaeckel@gmail.com> <sandro.jaeckel@sap.com>
TymanWasTaken <tbeckman530@gmail.com> <ty@blahaj.land>
================================================
FILE: .rustfmt.toml
================================================
reorder_imports = true
# uncomment once stable
#imports_granularity = "crate"
#group_imports = "StdExternalCrate"
================================================
FILE: AGENTS.md
================================================
# Atuin
Shell history tool. Replaces your shell's built-in history with a SQLite database, adds context (cwd, exit code, duration, hostname), and optionally syncs across machines with end-to-end encryption.
## Workspace crates
```
atuin CLI binary + TUI (clap, ratatui, crossterm)
atuin-client Client library: local DB, encryption, sync, settings
atuin-common Shared types, API models, utils
atuin-daemon Background gRPC daemon (tonic) for shell hooks
atuin-dotfiles Alias/var sync via record store
atuin-history Sorting algorithms, stats
atuin-kv Key-value store (synced)
atuin-scripts Script management (minijinja)
atuin-server HTTP sync server (axum) - lib + standalone binary
atuin-server-database Database trait for server
atuin-server-postgres Postgres implementation (sqlx)
atuin-server-sqlite SQLite implementation (sqlx)
```
## Two sync protocols
- **V1 (legacy)**: Syncs history entries directly. Being phased out. Toggleable via `sync_v1_enabled`.
- **V2 (current)**: Record store abstraction. All data types (history, KV, aliases, vars, scripts) share the same sync infrastructure using tagged records. Envelope-encrypted with PASETO V4 and per-record CEKs.
## Encryption
- **V1**: XSalsa20Poly1305 (secretbox). Key at `~/.local/share/atuin/key`.
- **V2**: PASETO V4 Local (XChaCha20-Poly1305 + Blake2b). Envelope encryption: each record gets a random CEK wrapped with the master key. Record metadata (id, idx, version, tag, host) is authenticated as implicit assertions.
## Databases
- **Client**: SQLite everywhere. Separate DBs for history, record store, KV, scripts. All use sqlx + WAL mode.
- **Server**: Postgres (primary) or SQLite. Auto-detected from URI prefix.
- Migrations live alongside each crate. Never modify existing migrations, only add new ones.
## Hot paths
`history start`, `history end`, and `init` skip database initialization for latency. Don't add DB calls to these without good reason.
## Conventions
- Rust 2024 edition, toolchain 1.93.1.
- Errors: `eyre::Result` in binaries, `thiserror` for typed errors in libraries.
- Async: tokio. Client uses `current_thread`; server uses `multi_thread`.
- `#![deny(unsafe_code)]` on client/common, `#![forbid(unsafe_code)]` on server.
- Clippy: `pedantic` + `nursery` on main crate. CI enforces `-D warnings -D clippy::redundant_clone`.
- Format: `cargo fmt`. Only non-default: `reorder_imports = true`.
- IDs: UUIDv7 (time-ordered), newtype wrappers (`HistoryId`, `RecordId`, `HostId`).
- Serialization: MessagePack for encrypted payloads, JSON for API, TOML for config.
- Storage traits: `Database` (client), `Store` (record store), `Database` (server) -- all `async_trait`.
- History builders: `HistoryImported`, `HistoryCaptured`, `HistoryFromDb` with compile-time field validation.
- Feature flags: `client`, `sync`, `daemon`, `clipboard`, `check-update`.
## Testing
- Unit tests inline with `#[cfg(test)]`, async via `#[tokio::test]`.
- Integration tests in `crates/atuin/tests/` need Postgres (`ATUIN_DB_URI` env var).
- Use `":memory:"` SQLite for unit tests needing a database.
- Runner: `cargo nextest`.
- Benchmarks: `divan` in `atuin-history`.
## Build and check
```sh
cargo build
cargo test
cargo clippy -- -D warnings
cargo fmt --check
```
================================================
FILE: CHANGELOG.md
================================================
# Changelog
All notable changes to this project will be documented in this file.
## [unreleased]
### Bug Fixes
- Nushell 0.111; future Nushell 0.112 support ([#3266](https://github.com/atuinsh/atuin/issues/3266))
### Features
- Call atuin setup from install script ([#3265](https://github.com/atuinsh/atuin/issues/3265))
- Allow headless account ops against Hub server ([#3280](https://github.com/atuinsh/atuin/issues/3280))
- Add custom filtering and scoring mechanisms
### Miscellaneous Tasks
- *(ci)* Migrate to depot runners ([#3279](https://github.com/atuinsh/atuin/issues/3279))
- *(ci)* Use depot to build docker images too ([#3281](https://github.com/atuinsh/atuin/issues/3281))
- Update changelog
- Update permissions in Docker workflow ([#3283](https://github.com/atuinsh/atuin/issues/3283))
- Change CHANGELOG format to be easier to parse
- Symlink changelog so dist can pick it up
- Vendor nucleo-ext + fork, so we can depend on our changes properly ([#3284](https://github.com/atuinsh/atuin/issues/3284))
## 18.13.2
### Miscellaneous Tasks
- *(release)* Building windows aarch64 was overly optimistic
- Update changelog
## 18.13.1
### Miscellaneous Tasks
- *(release)* Update dist, remove custom runners
- Update changelog
## 18.13.0
### Bug Fixes
- *(deps)* Add use-dev-tty to crossterm in atuin-ai ([#3185](https://github.com/atuinsh/atuin/issues/3185))
- *(docs)* Update Postgres volume path in Docker as required by pg18 ([#3174](https://github.com/atuinsh/atuin/issues/3174))
- Systemd Exec for separate server binary ([#3176](https://github.com/atuinsh/atuin/issues/3176))
- Multiline commands with fish ([#3179](https://github.com/atuinsh/atuin/issues/3179))
- Silent DB failures e.g. when disk is full ([#3183](https://github.com/atuinsh/atuin/issues/3183))
- Forward $PATH to tmux popup in zsh ([#3198](https://github.com/atuinsh/atuin/issues/3198))
- Dramatically decrease daemon memory usage ([#3211](https://github.com/atuinsh/atuin/issues/3211))
- Regen cargo dist
- Clear script database before rebuild to prevent unique constraint violation ([#3232](https://github.com/atuinsh/atuin/issues/3232))
- Support Nushell 0.111 ([#3249](https://github.com/atuinsh/atuin/issues/3249))
- Ctrl-c not exiting ai ([#3256](https://github.com/atuinsh/atuin/issues/3256))
### Documentation
- Update config.md to remove NuShell support note ([#3190](https://github.com/atuinsh/atuin/issues/3190))
- Document `search.filters` ([#3195](https://github.com/atuinsh/atuin/issues/3195))
- Clean up doc references for sqlite-based self-hosting ([#3216](https://github.com/atuinsh/atuin/issues/3216))
- Document daemon-fuzzy search mode ([#3254](https://github.com/atuinsh/atuin/issues/3254))
### Features
- *(docs)* Add Shell Integration and Interoperability docs ([#3163](https://github.com/atuinsh/atuin/issues/3163))
- `switch-context` ([#3149](https://github.com/atuinsh/atuin/issues/3149))
- Add Hub authentication for future sync + extra features ([#3010](https://github.com/atuinsh/atuin/issues/3010))
- Add Atuin AI inline CLI MVP ([#3178](https://github.com/atuinsh/atuin/issues/3178))
- Add autostart and pid management to daemon ([#3180](https://github.com/atuinsh/atuin/issues/3180))
- Generate commands or ask questions with `atuin ai` ([#3199](https://github.com/atuinsh/atuin/issues/3199))
- Add history author/intent metadata and v1 record version ([#3205](https://github.com/atuinsh/atuin/issues/3205))
- In-memory search index with atuin daemon ([#3201](https://github.com/atuinsh/atuin/issues/3201))
- Update script for smoother setup ([#3230](https://github.com/atuinsh/atuin/issues/3230))
- Initial draft of atuin-shell ([#3206](https://github.com/atuinsh/atuin/issues/3206))
- Allow setting multipliers for frequency, recency, and frecency scores ([#3235](https://github.com/atuinsh/atuin/issues/3235))
- Allow running `atuin search -i` as subcommand ([#3208](https://github.com/atuinsh/atuin/issues/3208))
- Use pty proxy for rendering tui popups without clearing the terminal ([#3234](https://github.com/atuinsh/atuin/issues/3234))
- Allow authenticating with Atuin Hub ([#3237](https://github.com/atuinsh/atuin/issues/3237))
- Initialize Atuin AI by default with `atuin init` ([#3255](https://github.com/atuinsh/atuin/issues/3255))
- Add `atuin setup` ([#3257](https://github.com/atuinsh/atuin/issues/3257))
### Miscellaneous Tasks
- Update changelog
- Update changelog
- Update changelog
- Use workspace versions ([#3210](https://github.com/atuinsh/atuin/issues/3210))
- Move atuin ai subcommand into core binary ([#3212](https://github.com/atuinsh/atuin/issues/3212))
- Update changelog
- Update to Rust 1.94 ([#3247](https://github.com/atuinsh/atuin/issues/3247))
- Strip symbols in dist profile to reduce binary size
- Upgrade thiserror 1.x to 2.x to deduplicate dependency
- Upgrade axum 0.7 to 0.8 to deduplicate with tonic's axum
- Update changelog
- Update changelog
- Update changelog
- Update changelog
## 18.12.1
### Bug Fixes
- *(shell)* Fix ATUIN_SESSION errors in tmux popup ([#3170](https://github.com/atuinsh/atuin/issues/3170))
- *(tui)* Enter in vim normal mode, shift-tab keybind ([#3158](https://github.com/atuinsh/atuin/issues/3158))
- Server start commands for Docker. ([#3160](https://github.com/atuinsh/atuin/issues/3160))
### Features
- Expand keybinding system with vim motions, media keys, and inspector improvements ([#3161](https://github.com/atuinsh/atuin/issues/3161))
- Add original-input-empty keybind condition ([#3171](https://github.com/atuinsh/atuin/issues/3171))
### Miscellaneous Tasks
- Update changelog
## 18.12.0
### Bug Fixes
- *(powershell)* Preserve `$LASTEXITCODE` ([#3120](https://github.com/atuinsh/atuin/issues/3120))
- *(powershell)* Display search stderr ([#3146](https://github.com/atuinsh/atuin/issues/3146))
- *(search)* Allow hyphen-prefixed query args like `---` ([#3129](https://github.com/atuinsh/atuin/issues/3129))
- *(tui)* Space and F1-F24 keys not handled properly by new keybind system ([#3138](https://github.com/atuinsh/atuin/issues/3138))
- *(ui)* Don't draw a leading space for command
- *(ui)* Time column can take up to 9 cells
- *(ui)* Align cursor with the expand column (usually the command)
- *(ui)* Align cursor when expand column is in the middle ([#3103](https://github.com/atuinsh/atuin/issues/3103))
- Zsh import multiline issue ([#2799](https://github.com/atuinsh/atuin/issues/2799))
- Do not hit sync v1 endpoints for status
- Do not hit sync v1 endpoints for status ([#3102](https://github.com/atuinsh/atuin/issues/3102))
- Do not set ATUIN_SESSION if it is already set ([#3107](https://github.com/atuinsh/atuin/issues/3107))
- Custom data dir test on windows ([#3109](https://github.com/atuinsh/atuin/issues/3109))
- New session on shlvl change ([#3111](https://github.com/atuinsh/atuin/issues/3111))
- Larger exit column width on Windows ([#3119](https://github.com/atuinsh/atuin/issues/3119))
- Halt sync loop if server returns an empty page ([#3122](https://github.com/atuinsh/atuin/issues/3122))
- Use directories crate for home dir resolution ([#3125](https://github.com/atuinsh/atuin/issues/3125))
- Tab behaving like enter, eprintln ([#3135](https://github.com/atuinsh/atuin/issues/3135))
- Issue with shift and modifier keys ([#3143](https://github.com/atuinsh/atuin/issues/3143))
- Remove invalid IF EXISTS from sqlite drop column migration ([#3145](https://github.com/atuinsh/atuin/issues/3145))
### Documentation
- *(CONTRIBUTING)* Update links ([#3117](https://github.com/atuinsh/atuin/issues/3117))
- *(README)* Update links ([#3116](https://github.com/atuinsh/atuin/issues/3116))
- *(config)* Clarify scope of directory filter_mode ([#3082](https://github.com/atuinsh/atuin/issues/3082))
- *(configuration)* Describe new utility "atuin-bind" for Bash ([#3064](https://github.com/atuinsh/atuin/issues/3064))
- *(installation)* Add mise alternative installation method ([#3066](https://github.com/atuinsh/atuin/issues/3066))
- Various improvements to the `atuin import` docs ([#3062](https://github.com/atuinsh/atuin/issues/3062))
- Disambiguate 'setup' (noun) vs. 'set up' (verb) ([#3061](https://github.com/atuinsh/atuin/issues/3061))
- Fix punctuation and grammar in basic usage guide ([#3063](https://github.com/atuinsh/atuin/issues/3063))
- Expand and clarify usage of the history prune command ([#3084](https://github.com/atuinsh/atuin/issues/3084))
- Small edit to themes website file ([#3069](https://github.com/atuinsh/atuin/issues/3069))
- Config/ with initial uid:gid
- Add PowerShell install instructions
- Add PowerShell and Windows install instructions ([#3096](https://github.com/atuinsh/atuin/issues/3096))
- Update the `[keys]` docs ([#3114](https://github.com/atuinsh/atuin/issues/3114))
- Add history deletion guide ([#3130](https://github.com/atuinsh/atuin/issues/3130))
- Update how to use Docker to self-host ([#3148](https://github.com/atuinsh/atuin/issues/3148))
- Add IRC contact information to README
### Features
- *(dotfiles)* Add sort and filter options to alias/var list ([#3131](https://github.com/atuinsh/atuin/issues/3131))
- *(theme)* Note new default theme name and syntax ([#3080](https://github.com/atuinsh/atuin/issues/3080))
- *(tui)* Add clear-to-start/end actions ([#3141](https://github.com/atuinsh/atuin/issues/3141))
- *(ui)* Highlight fulltext search as fulltext search instead of fuzzy search
- *(ui)* Highlight fulltext search as fulltext search instead of fuzzy search ([#3098](https://github.com/atuinsh/atuin/issues/3098))
- *(ultracompact)* Adds setting for ultracompact mode ([#3079](https://github.com/atuinsh/atuin/issues/3079))
- Add custom column support ([#3089](https://github.com/atuinsh/atuin/issues/3089))
- Left arrow/backspace on empty to start edit ([#3090](https://github.com/atuinsh/atuin/issues/3090))
- Add more vim movement bindings for navigation ([#3041](https://github.com/atuinsh/atuin/issues/3041))
- Support setting a custom data dir in config ([#3105](https://github.com/atuinsh/atuin/issues/3105))
- Remove user verification functionality ([#3108](https://github.com/atuinsh/atuin/issues/3108))
- Add option to use tmux display-popup ([#3058](https://github.com/atuinsh/atuin/issues/3058))
- Move atuin-server to its own binary ([#3112](https://github.com/atuinsh/atuin/issues/3112))
- Add a parameter to the sync to specify the download/upload page ([#2408](https://github.com/atuinsh/atuin/issues/2408))
- Replace several files with a sqlite db ([#3128](https://github.com/atuinsh/atuin/issues/3128))
- Add new custom keybinding system for search TUI ([#3127](https://github.com/atuinsh/atuin/issues/3127))
### Miscellaneous Tasks
- Remove total_history from api index response ([#3094](https://github.com/atuinsh/atuin/issues/3094))
- **BREAKING**: remove total_history from api index response ([#3094](https://github.com/atuinsh/atuin/issues/3094))
- Update to rust 1.93
- Update to rust 1.93 ([#3101](https://github.com/atuinsh/atuin/issues/3101))
- Update changelog
- Update agents.md ([#3126](https://github.com/atuinsh/atuin/issues/3126))
- Update changelog
- Update changelog
- Update changelog
### Theming
- Explain how to set ANSI codes directly ([#3065](https://github.com/atuinsh/atuin/issues/3065))
### Faq
- Add alternative projects ([#3076](https://github.com/atuinsh/atuin/issues/3076))
## 18.11.0
### Bug Fixes
- *(bash)* Fix issues with intermediate key sequences in the vi editing mode ([#2977](https://github.com/atuinsh/atuin/issues/2977))
- *(bash)* Work around a keybinding bug of Bash 5.1 ([#2975](https://github.com/atuinsh/atuin/issues/2975))
- *(bash/blesh)* Suppress error message for auto-complete source ([#2976](https://github.com/atuinsh/atuin/issues/2976))
- *(powershell)* Run `atuin history end` in the background ([#3034](https://github.com/atuinsh/atuin/issues/3034))
- *(powershell)* Add error safety and cleanup ([#3040](https://github.com/atuinsh/atuin/issues/3040))
- Highlight the correct place when multibyte characters are involved ([#2965](https://github.com/atuinsh/atuin/issues/2965))
- Prevent interactive search crash when update check fails ([#3016](https://github.com/atuinsh/atuin/issues/3016))
- Move thorough search through search.filters w/ workspaces ([#2703](https://github.com/atuinsh/atuin/issues/2703))
### Documentation
- Migrate docs from separate repo to `docs` subfolder ([#3018](https://github.com/atuinsh/atuin/issues/3018))
### Features
- Support additional history filenames in replxx importer ([#3005](https://github.com/atuinsh/atuin/issues/3005))
- Add colors to --help/-h ([#3000](https://github.com/atuinsh/atuin/issues/3000))
- Add support for read replicas to postgres ([#3029](https://github.com/atuinsh/atuin/issues/3029))
- Allow disabling sync v1 ([#3030](https://github.com/atuinsh/atuin/issues/3030))
- Consider atuin dotfile aliases when calculating atuin wrapped ([#3048](https://github.com/atuinsh/atuin/issues/3048))
- Add session and uuid column support to history list ([#3049](https://github.com/atuinsh/atuin/issues/3049))
### Miscellaneous Tasks
- *(nix)* Prevent deprecation warning on evaluation ([#3006](https://github.com/atuinsh/atuin/issues/3006))
- Update changelog
- Adjust update wording ([#2974](https://github.com/atuinsh/atuin/issues/2974))
- Add Windows builds, second try ([#2966](https://github.com/atuinsh/atuin/issues/2966))
- Update to rust 1.91 ([#2981](https://github.com/atuinsh/atuin/issues/2981))
- Add Atuin Desktop information to install script
- Remove trailing whitespace ([#2985](https://github.com/atuinsh/atuin/issues/2985))
- Fix typo ([#2994](https://github.com/atuinsh/atuin/issues/2994))
- Clarify docstring of the enter_accept config key ([#3003](https://github.com/atuinsh/atuin/issues/3003))
- Fix github action syntax for variables ([#2998](https://github.com/atuinsh/atuin/issues/2998))
- Add AGENTS.md
- Update changelog
- Remove x86_64 mac from build targets ([#3052](https://github.com/atuinsh/atuin/issues/3052))
### Build
- *(nix)* Update rust toolchain hash ([#2990](https://github.com/atuinsh/atuin/issues/2990))
## 18.10.0
### Bug Fixes
- Stats ngram window size cli parsing ([#2946](https://github.com/atuinsh/atuin/issues/2946))
### Features
- *(bash)* Use Readline's accept-line for enter_accept ([#2953](https://github.com/atuinsh/atuin/issues/2953))
- Add commit to displayed version info ([#2922](https://github.com/atuinsh/atuin/issues/2922))
- Add import from PowerShell history ([#2864](https://github.com/atuinsh/atuin/issues/2864))
- Interactive Inspector ([#2319](https://github.com/atuinsh/atuin/issues/2319))
- Nu ≥ 0.106.0 support commandline accept ([#2957](https://github.com/atuinsh/atuin/issues/2957))
### Miscellaneous Tasks
- Update rusty_paseto and rusty_paserk ([#2942](https://github.com/atuinsh/atuin/issues/2942))
- Update changelog
## 18.9.0
### Bug Fixes
- *(dotfiles)* Properly escape spaces/quotes in vars
- Clippy issues on Windows ([#2856](https://github.com/atuinsh/atuin/issues/2856))
- Honor timezone in inspector stats ([#2853](https://github.com/atuinsh/atuin/issues/2853))
- Make status exit 1 if not logged in ([#2843](https://github.com/atuinsh/atuin/issues/2843))
- Match logic of theme directory with settings directory, so ATUIN_CONFIG_DIR is respected ([#2707](https://github.com/atuinsh/atuin/issues/2707))
- Expand path for daemon.socket_path ([#2870](https://github.com/atuinsh/atuin/issues/2870))
- Use fullscreen if `inline_height` is too large ([#2888](https://github.com/atuinsh/atuin/issues/2888))
- Clean up new rustc and clippy warnings on Rust 1.89
- `cargo update` and changes needed to accomodate it
- Run `cargo fmt`
- Clippy warnings I don't have on my version of clippy
- Add forgotten `rust-toolchain.toml` to match changes (oops)
- Update version in Cargo.toml + github workflows
- Clippy warnings
- Dissociate command_chaining from enter_accept
- Remove __atuin_chain_command__ prefix
- Docker compose link ([#2914](https://github.com/atuinsh/atuin/issues/2914))
- Fish up binding ([#2902](https://github.com/atuinsh/atuin/issues/2902))
### Features
- *(stats)* Add dotnet to default common subcommands
- *(tui)* Select entries using number in vim-normal mode. closes #2368 ([#2893](https://github.com/atuinsh/atuin/issues/2893))
- *(tui)* Add show_numeric_shortcuts config to hide 1-9 shortcuts ([#2766](https://github.com/atuinsh/atuin/issues/2766))
- Highlight matches in interactive search ([#2653](https://github.com/atuinsh/atuin/issues/2653))
- Add session-preload filter mode to include global history from before session start
- Add various acceptance keys ([#2928](https://github.com/atuinsh/atuin/issues/2928))
- More accurately filter secret tokens ([#2932](https://github.com/atuinsh/atuin/issues/2932))
- Add shell pipelines to command chaining ([#2938](https://github.com/atuinsh/atuin/issues/2938))
### Miscellaneous Tasks
- Update changelog
- Remove legacy Apple SDK frameworks ([#2885](https://github.com/atuinsh/atuin/issues/2885))
- Update dist workflows
- Update to Rust 1.90 ([#2916](https://github.com/atuinsh/atuin/issues/2916))
### Refactor
- Shell environment variables
### Build
- Update flake.nix with new sha256
## 18.8.0
### Bug Fixes
- *(build)* Enable sqlite feature for sqlite server ([#2848](https://github.com/atuinsh/atuin/issues/2848))
- Make login exit 1 if already logged in ([#2832](https://github.com/atuinsh/atuin/issues/2832))
- Use transaction for idx consistency checking ([#2840](https://github.com/atuinsh/atuin/issues/2840))
- Ensure the idx cache is cleaned on deletion, only insert if records are inserted ([#2841](https://github.com/atuinsh/atuin/issues/2841))
### Features
- Command chaining ([#2834](https://github.com/atuinsh/atuin/issues/2834))
- Add info for 'official' plugins ([#2835](https://github.com/atuinsh/atuin/issues/2835))
- Support multi part commands ([#2836](https://github.com/atuinsh/atuin/issues/2836)) ([#2837](https://github.com/atuinsh/atuin/issues/2837))
- Add inline_height_shell_up_key_binding option ([#2817](https://github.com/atuinsh/atuin/issues/2817))
- Add IDX_CACHE_ROLLOUT ([#2850](https://github.com/atuinsh/atuin/issues/2850))
### Miscellaneous Tasks
- Update to rust 1.88 ([#2815](https://github.com/atuinsh/atuin/issues/2815))
### Nushell
- Fix `get -i` deprecation ([#2829](https://github.com/atuinsh/atuin/issues/2829))
## 18.7.1
### Bug Fixes
- Add check for postgresql prefix ([#2825](https://github.com/atuinsh/atuin/issues/2825))
### Miscellaneous Tasks
- Update changelog
## 18.7.0
### Bug Fixes
- *(api)* Allow trailing slashes in sync_address ([#2760](https://github.com/atuinsh/atuin/issues/2760))
- *(doctor)* Mention the required ble.sh version ([#2774](https://github.com/atuinsh/atuin/issues/2774))
- *(search)* Prevent panic on malformed format strings ([#2776](https://github.com/atuinsh/atuin/issues/2776)) ([#2777](https://github.com/atuinsh/atuin/issues/2777))
- Clarify that HISTFILE, if used, must be exported ([#2758](https://github.com/atuinsh/atuin/issues/2758))
- Don't print errors in `zsh_autosuggest` helper ([#2780](https://github.com/atuinsh/atuin/issues/2780))
- `atuin.nu` enchancements ([#2778](https://github.com/atuinsh/atuin/issues/2778))
- Refuse "--dupkeep 0" ([#2807](https://github.com/atuinsh/atuin/issues/2807))
### Features
- Add sqlite server support for self-hosting ([#2770](https://github.com/atuinsh/atuin/issues/2770))
### Miscellaneous Tasks
- *(ci)* Install toolchain that matches rust-toolchain.toml ([#2759](https://github.com/atuinsh/atuin/issues/2759))
- Allow setting script DB path ([#2750](https://github.com/atuinsh/atuin/issues/2750))
## 18.6.1
### Bug Fixes
- Selection vs render issue ([#2706](https://github.com/atuinsh/atuin/issues/2706))
### Features
- *(stats)* Add jj to default common subcommands ([#2708](https://github.com/atuinsh/atuin/issues/2708))
- Delete duplicate history ([#2697](https://github.com/atuinsh/atuin/issues/2697))
- Sort `atuin store status` output ([#2719](https://github.com/atuinsh/atuin/issues/2719))
- Implement KV as a write-through cache ([#2732](https://github.com/atuinsh/atuin/issues/2732))
### Miscellaneous Tasks
- Use native github arm64 runner ([#2690](https://github.com/atuinsh/atuin/issues/2690))
- Fix typos ([#2668](https://github.com/atuinsh/atuin/issues/2668))
## 18.5.0
### Bug Fixes
- *(1289)* Clear terminal area if inline ([#2600](https://github.com/atuinsh/atuin/issues/2600))
- *(bash)* Fix preexec of child Bash session started by enter_accept ([#2558](https://github.com/atuinsh/atuin/issues/2558))
- *(build)* Change atuin-daemon build script .proto paths ([#2638](https://github.com/atuinsh/atuin/issues/2638))
- *(kv)* Filter deleted keys from `kv list` ([#2665](https://github.com/atuinsh/atuin/issues/2665))
- *(stats)* Ignore leading environment variables when calculating stats ([#2659](https://github.com/atuinsh/atuin/issues/2659))
- *(wrapped)* Fix crash when history is empty ([#2508](https://github.com/atuinsh/atuin/issues/2508))
- *(zsh)* Fix an error introduced earilier with support for bracketed paste mode ([#2651](https://github.com/atuinsh/atuin/issues/2651))
- *(zsh)* Avoid calling user-defined widgets when searching for history position ([#2670](https://github.com/atuinsh/atuin/issues/2670))
- Add .histfile as file to look for when doing atuin import zsh ([#2588](https://github.com/atuinsh/atuin/issues/2588))
- Panic when invoking delete on empty tui ([#2584](https://github.com/atuinsh/atuin/issues/2584))
- Sql files checksums ([#2601](https://github.com/atuinsh/atuin/issues/2601))
- Up binding with fish 4.0 ([#2613](https://github.com/atuinsh/atuin/issues/2613)) ([#2616](https://github.com/atuinsh/atuin/issues/2616))
- Don't save empty commands ([#2605](https://github.com/atuinsh/atuin/issues/2605))
- Improve broken symlink error handling ([#2589](https://github.com/atuinsh/atuin/issues/2589))
- Multiline command does not honour max_preview_height ([#2624](https://github.com/atuinsh/atuin/issues/2624))
- Typeerror in client sync code ([#2647](https://github.com/atuinsh/atuin/issues/2647))
- Add redundant clones to clippy and cleanup instances of it ([#2654](https://github.com/atuinsh/atuin/issues/2654))
- Allow -ve values for timezone ([#2609](https://github.com/atuinsh/atuin/issues/2609))
- Fish up binding bug ([#2677](https://github.com/atuinsh/atuin/issues/2677))
- Switch to astral cargo-dist ([#2687](https://github.com/atuinsh/atuin/issues/2687))
### Documentation
- Update logo and badges in README for zh-CN ([#2392](https://github.com/atuinsh/atuin/issues/2392))
### Features
- *(client)* Update AWS secrets env var handling checks ([#2501](https://github.com/atuinsh/atuin/issues/2501))
- *(health)* Add health check endpoint at `/healthz` ([#2549](https://github.com/atuinsh/atuin/issues/2549))
- *(kv)* Add support for 'atuin kv delete' ([#2660](https://github.com/atuinsh/atuin/issues/2660))
- *(wrapped)* Add more pkg managers ([#2503](https://github.com/atuinsh/atuin/issues/2503))
- *(zsh)* Try to go to the position in zsh's history ([#1469](https://github.com/atuinsh/atuin/issues/1469))
- *(zsh)* Re-enable bracketed paste ([#2646](https://github.com/atuinsh/atuin/issues/2646))
- Add the --print0 option to search ([#2562](https://github.com/atuinsh/atuin/issues/2562))
- Make new arrow key behavior configurable ([#2606](https://github.com/atuinsh/atuin/issues/2606))
- Use readline binding for ctrl-a when it is not the prefix ([#2626](https://github.com/atuinsh/atuin/issues/2626))
- Option to include duplicate commands when printing history commands ([#2407](https://github.com/atuinsh/atuin/issues/2407))
- Binaries as subcommands ([#2661](https://github.com/atuinsh/atuin/issues/2661))
- Support storing, syncing and executing scripts ([#2644](https://github.com/atuinsh/atuin/issues/2644))
- Add 'atuin scripts rm' and 'atuin scripts ls' aliases; allow reading from stdin ([#2680](https://github.com/atuinsh/atuin/issues/2680))
### Miscellaneous Tasks
- Remove unneeded dependencies ([#2523](https://github.com/atuinsh/atuin/issues/2523))
- Update rust toolchain to 1.85 ([#2618](https://github.com/atuinsh/atuin/issues/2618))
- Align daemon and client sync freq ([#2628](https://github.com/atuinsh/atuin/issues/2628))
- Migrate to rust 2024 ([#2635](https://github.com/atuinsh/atuin/issues/2635))
- Show host and user in inspector ([#2634](https://github.com/atuinsh/atuin/issues/2634))
- Update to rust 1.85.1 ([#2642](https://github.com/atuinsh/atuin/issues/2642))
- Update to rust 1.86 ([#2666](https://github.com/atuinsh/atuin/issues/2666))
### Performance
- Cache `SECRET_PATTERNS`'s `RegexSet` ([#2570](https://github.com/atuinsh/atuin/issues/2570))
### Styling
- Avoid calling `unwrap()` when we don't have to ([#2519](https://github.com/atuinsh/atuin/issues/2519))
### Build
- *(nix)* Bump `flake.lock` ([#2637](https://github.com/atuinsh/atuin/issues/2637))
### Flake.lock
- Update ([#2463](https://github.com/atuinsh/atuin/issues/2463))
## 18.4.0
### Bug Fixes
- *(crate)* Add missing description ([#2106](https://github.com/atuinsh/atuin/issues/2106))
- *(crate)* Add description to daemon crate ([#2107](https://github.com/atuinsh/atuin/issues/2107))
- *(daemon)* Add context to error when unable to connect ([#2394](https://github.com/atuinsh/atuin/issues/2394))
- *(deps)* Pin tiny_bip to 1.0.0 until breaking change resolved ([#2412](https://github.com/atuinsh/atuin/issues/2412))
- *(docker)* Update Dockerfile ([#2369](https://github.com/atuinsh/atuin/issues/2369))
- *(gui)* Update deps ([#2116](https://github.com/atuinsh/atuin/issues/2116))
- *(gui)* Add support for checking if the cli is installed on windows ([#2162](https://github.com/atuinsh/atuin/issues/2162))
- *(gui)* WeekInfo call on Edge ([#2252](https://github.com/atuinsh/atuin/issues/2252))
- *(gui)* Add \r for windows (shouldn't effect unix bc they should ignore it) ([#2253](https://github.com/atuinsh/atuin/issues/2253))
- *(gui)* Terminal resize overflow ([#2285](https://github.com/atuinsh/atuin/issues/2285))
- *(gui)* Kill child on block stop ([#2288](https://github.com/atuinsh/atuin/issues/2288))
- *(gui)* Do not hardcode db path ([#2309](https://github.com/atuinsh/atuin/issues/2309))
- *(gui)* Double return on mac/linux ([#2311](https://github.com/atuinsh/atuin/issues/2311))
- *(gui)* Cursor positioning on new doc creation ([#2310](https://github.com/atuinsh/atuin/issues/2310))
- *(gui)* Random ts errors ([#2316](https://github.com/atuinsh/atuin/issues/2316))
- *(history)* Logic for store_failed=false ([#2284](https://github.com/atuinsh/atuin/issues/2284))
- *(mail)* Incorrect alias and error logs ([#2346](https://github.com/atuinsh/atuin/issues/2346))
- *(mail)* Enable correct tls features for postmark client ([#2347](https://github.com/atuinsh/atuin/issues/2347))
- *(theme)* Restore original colours ([#2339](https://github.com/atuinsh/atuin/issues/2339))
- *(themes)* Restore default theme, refactor ([#2294](https://github.com/atuinsh/atuin/issues/2294))
- *(tui)* Press ctrl-a twice should jump to beginning of line ([#2246](https://github.com/atuinsh/atuin/issues/2246))
- *(tui)* Don't panic when search result is empty and up is pressed ([#2395](https://github.com/atuinsh/atuin/issues/2395))
- Cargo binstall config ([#2112](https://github.com/atuinsh/atuin/issues/2112))
- Unitless sync_frequence = 0 not parsed by humantime ([#2154](https://github.com/atuinsh/atuin/issues/2154))
- Some --help comments didn't show properly ([#2176](https://github.com/atuinsh/atuin/issues/2176))
- Ensure we cleanup all tables when deleting ([#2191](https://github.com/atuinsh/atuin/issues/2191))
- Add idx cache unique index ([#2226](https://github.com/atuinsh/atuin/issues/2226))
- Idx cache inconsistency ([#2231](https://github.com/atuinsh/atuin/issues/2231))
- Ambiguous column name ([#2232](https://github.com/atuinsh/atuin/issues/2232))
- Atuin-daemon optional dependency ([#2306](https://github.com/atuinsh/atuin/issues/2306))
- Windows build error ([#2321](https://github.com/atuinsh/atuin/issues/2321))
- Codespell config still references the ui ([#2330](https://github.com/atuinsh/atuin/issues/2330))
- Remove dbg! macro ([#2355](https://github.com/atuinsh/atuin/issues/2355))
- Disable mail by default, resolve #2404 ([#2405](https://github.com/atuinsh/atuin/issues/2405))
- Time offset display in `atuin status` ([#2433](https://github.com/atuinsh/atuin/issues/2433))
- Disable the actuated mirror on the x86 docker builder ([#2443](https://github.com/atuinsh/atuin/issues/2443))
### Documentation
- *(README)* Fix broken link ([#2206](https://github.com/atuinsh/atuin/issues/2206))
- *(gui)* Update README ([#2283](https://github.com/atuinsh/atuin/issues/2283))
- Streamline readme ([#2203](https://github.com/atuinsh/atuin/issues/2203))
- Update quickstart install command ([#2205](https://github.com/atuinsh/atuin/issues/2205))
### Features
- *(bash/blesh)* Hook into BLE_ONLOAD to resolve loading order issue ([#2234](https://github.com/atuinsh/atuin/issues/2234))
- *(client)* Add filter mode enablement and ordering configuration ([#2430](https://github.com/atuinsh/atuin/issues/2430))
- *(daemon)* Follow XDG_RUNTIME_DIR if set ([#2171](https://github.com/atuinsh/atuin/issues/2171))
- *(gui)* Automatically install and setup the cli/shell ([#2139](https://github.com/atuinsh/atuin/issues/2139))
- *(gui)* Add activity calendar to the homepage ([#2160](https://github.com/atuinsh/atuin/issues/2160))
- *(gui)* Cache zustand store in localstorage ([#2168](https://github.com/atuinsh/atuin/issues/2168))
- *(gui)* Toast with prompt for cli install, rather than auto ([#2173](https://github.com/atuinsh/atuin/issues/2173))
- *(gui)* Runbooks that run ([#2233](https://github.com/atuinsh/atuin/issues/2233))
- *(gui)* Use fancy new side nav ([#2243](https://github.com/atuinsh/atuin/issues/2243))
- *(gui)* Add runbook list, ability to create and delete, sql storage ([#2282](https://github.com/atuinsh/atuin/issues/2282))
- *(gui)* Background terminals and more ([#2303](https://github.com/atuinsh/atuin/issues/2303))
- *(gui)* Clean up home page, fix a few bugs ([#2304](https://github.com/atuinsh/atuin/issues/2304))
- *(gui)* Allow interacting with the embedded terminal ([#2312](https://github.com/atuinsh/atuin/issues/2312))
- *(gui)* Directory block, re-org of some code ([#2314](https://github.com/atuinsh/atuin/issues/2314))
- *(gui)* Folder select dialogue for directory block ([#2315](https://github.com/atuinsh/atuin/issues/2315))
- *(history)* Filter out various environment variables containing potential secrets ([#2174](https://github.com/atuinsh/atuin/issues/2174))
- *(tui)* Configurable prefix character ([#2157](https://github.com/atuinsh/atuin/issues/2157))
- *(tui)* Customizable Themes ([#2236](https://github.com/atuinsh/atuin/issues/2236))
- *(tui)* Fixed preview height option ([#2286](https://github.com/atuinsh/atuin/issues/2286))
- Use cargo-dist installer from our install script ([#2108](https://github.com/atuinsh/atuin/issues/2108))
- Add user account verification ([#2190](https://github.com/atuinsh/atuin/issues/2190))
- Add GitLab PAT to secret patterns ([#2196](https://github.com/atuinsh/atuin/issues/2196))
- Add several other GitHub access token patterns ([#2200](https://github.com/atuinsh/atuin/issues/2200))
- Add npm, Netlify and Pulumi tokens to secret patterns ([#2210](https://github.com/atuinsh/atuin/issues/2210))
- Allow advertising a fake version to clients ([#2228](https://github.com/atuinsh/atuin/issues/2228))
- Monitor idx cache consistency before switching ([#2229](https://github.com/atuinsh/atuin/issues/2229))
- Ultracompact Mode (search-only) ([#2357](https://github.com/atuinsh/atuin/issues/2357))
- Right Arrow to modify selected command ([#2453](https://github.com/atuinsh/atuin/issues/2453))
- Provide additional clarity around key management ([#2467](https://github.com/atuinsh/atuin/issues/2467))
- Add `atuin wrapped` ([#2493](https://github.com/atuinsh/atuin/issues/2493))
### Miscellaneous Tasks
- *(build)* Compile protobufs with protox ([#2122](https://github.com/atuinsh/atuin/issues/2122))
- *(ci)* Do not run current ci for ui ([#2189](https://github.com/atuinsh/atuin/issues/2189))
- *(ci)* Codespell again ([#2332](https://github.com/atuinsh/atuin/issues/2332))
- *(deps-dev)* Bump @tauri-apps/cli in /ui ([#2135](https://github.com/atuinsh/atuin/issues/2135))
- *(deps-dev)* Bump vite from 5.2.13 to 5.3.1 in /ui ([#2150](https://github.com/atuinsh/atuin/issues/2150))
- *(deps-dev)* Bump @tauri-apps/cli in /ui ([#2277](https://github.com/atuinsh/atuin/issues/2277))
- *(deps-dev)* Bump tailwindcss from 3.4.4 to 3.4.6 in /ui ([#2301](https://github.com/atuinsh/atuin/issues/2301))
- *(install)* Use posix sh, not bash ([#2204](https://github.com/atuinsh/atuin/issues/2204))
- *(nix)* De-couple atuin nix build from nixpkgs rustc version ([#2123](https://github.com/atuinsh/atuin/issues/2123))
- Add installer e2e tests ([#2110](https://github.com/atuinsh/atuin/issues/2110))
- Remove unnecessary proto import ([#2120](https://github.com/atuinsh/atuin/issues/2120))
- Update to rust 1.78
- Add audit config, ignore RUSTSEC-2023-0071 ([#2126](https://github.com/atuinsh/atuin/issues/2126))
- Setup dependabot for the ui ([#2128](https://github.com/atuinsh/atuin/issues/2128))
- Cargo and pnpm update ([#2127](https://github.com/atuinsh/atuin/issues/2127))
- Update to rust 1.79 ([#2138](https://github.com/atuinsh/atuin/issues/2138))
- Update to cargo-dist 0.16, enable attestations ([#2156](https://github.com/atuinsh/atuin/issues/2156))
- Do not use package managers in installer ([#2201](https://github.com/atuinsh/atuin/issues/2201))
- Enable record sync by default ([#2255](https://github.com/atuinsh/atuin/issues/2255))
- Remove ui directory ([#2329](https://github.com/atuinsh/atuin/issues/2329))
- Update to rust 1.80 ([#2344](https://github.com/atuinsh/atuin/issues/2344))
- Update rust to `1.80.1` ([#2362](https://github.com/atuinsh/atuin/issues/2362))
- Enable inline height and compact by default ([#2249](https://github.com/atuinsh/atuin/issues/2249))
- Update to rust 1.82 ([#2432](https://github.com/atuinsh/atuin/issues/2432))
- Update cargo-dist ([#2471](https://github.com/atuinsh/atuin/issues/2471))
### Performance
- *(search)* Benchmark smart sort ([#2202](https://github.com/atuinsh/atuin/issues/2202))
- Create idx cache table ([#2140](https://github.com/atuinsh/atuin/issues/2140))
- Write to the idx cache ([#2225](https://github.com/atuinsh/atuin/issues/2225))
### Testing
- Add env ATUIN_TEST_LOCAL_TIMEOUT to control test timeout of SQLite ([#2337](https://github.com/atuinsh/atuin/issues/2337))
### Flake.lock
- Update ([#2213](https://github.com/atuinsh/atuin/issues/2213))
- Update ([#2378](https://github.com/atuinsh/atuin/issues/2378))
- Update ([#2402](https://github.com/atuinsh/atuin/issues/2402))
## 18.3.0
### Bug Fixes
- *(bash)* Fix a workaround for bash-5.2 keybindings ([#2060](https://github.com/atuinsh/atuin/issues/2060))
- *(ci)* Release workflow ([#1978](https://github.com/atuinsh/atuin/issues/1978))
- *(client)* Better error reporting on login/registration ([#2076](https://github.com/atuinsh/atuin/issues/2076))
- *(config)* Add quotes for strategy value in comment ([#1993](https://github.com/atuinsh/atuin/issues/1993))
- *(daemon)* Do not try to sync if logged out ([#2037](https://github.com/atuinsh/atuin/issues/2037))
- *(deps)* Replace parse_duration with humantime ([#2074](https://github.com/atuinsh/atuin/issues/2074))
- *(dotfiles)* Alias import with init output ([#1970](https://github.com/atuinsh/atuin/issues/1970))
- *(dotfiles)* Fish alias import ([#1972](https://github.com/atuinsh/atuin/issues/1972))
- *(dotfiles)* More fish alias import ([#1974](https://github.com/atuinsh/atuin/issues/1974))
- *(dotfiles)* Unquote aliases before quoting ([#1976](https://github.com/atuinsh/atuin/issues/1976))
- *(dotfiles)* Allow clearing aliases, disable import ([#1995](https://github.com/atuinsh/atuin/issues/1995))
- *(stats)* Generation for commands starting with a pipe ([#2058](https://github.com/atuinsh/atuin/issues/2058))
- *(ui)* Handle being logged out gracefully ([#2052](https://github.com/atuinsh/atuin/issues/2052))
- *(ui)* Fix mistake in last pr ([#2053](https://github.com/atuinsh/atuin/issues/2053))
- Support not-mac for default shell ([#1960](https://github.com/atuinsh/atuin/issues/1960))
- Adapt help to `enter_accept` config ([#2001](https://github.com/atuinsh/atuin/issues/2001))
- Add protobuf compiler to docker image ([#2009](https://github.com/atuinsh/atuin/issues/2009))
- Add incremental rebuild to daemon loop ([#2010](https://github.com/atuinsh/atuin/issues/2010))
- Alias enable/enabled in settings ([#2021](https://github.com/atuinsh/atuin/issues/2021))
- Bogus error message wording ([#1283](https://github.com/atuinsh/atuin/issues/1283))
- Save sync time in daemon ([#2029](https://github.com/atuinsh/atuin/issues/2029))
- Redact password in database URI when logging ([#2032](https://github.com/atuinsh/atuin/issues/2032))
- Save sync time in daemon ([#2051](https://github.com/atuinsh/atuin/issues/2051))
- Replace serde_yaml::to_string with serde_json::to_string_yaml ([#2087](https://github.com/atuinsh/atuin/issues/2087))
### Documentation
- Fix "From source" `cd` command ([#1973](https://github.com/atuinsh/atuin/issues/1973))
- Add docs for store subcommand ([#2097](https://github.com/atuinsh/atuin/issues/2097))
### Features
- *(daemon)* Add support for daemon on windows ([#2014](https://github.com/atuinsh/atuin/issues/2014))
- *(doctor)* Detect active preexec framework ([#1955](https://github.com/atuinsh/atuin/issues/1955))
- *(doctor)* Report sqlite version ([#2075](https://github.com/atuinsh/atuin/issues/2075))
- *(dotfiles)* Support syncing shell/env vars ([#1977](https://github.com/atuinsh/atuin/issues/1977))
- *(gui)* Work on home page, sort state ([#1956](https://github.com/atuinsh/atuin/issues/1956))
- *(history)* Create atuin-history, add stats to it ([#1990](https://github.com/atuinsh/atuin/issues/1990))
- *(install)* Add Tuxedo OS ([#2018](https://github.com/atuinsh/atuin/issues/2018))
- *(server)* Add me endpoint ([#1954](https://github.com/atuinsh/atuin/issues/1954))
- *(ui)* Scroll history infinitely ([#1999](https://github.com/atuinsh/atuin/issues/1999))
- *(ui)* Add history explore ([#2022](https://github.com/atuinsh/atuin/issues/2022))
- *(ui)* Use correct username on welcome screen ([#2050](https://github.com/atuinsh/atuin/issues/2050))
- *(ui)* Add login/register dialog ([#2056](https://github.com/atuinsh/atuin/issues/2056))
- *(ui)* Setup single-instance ([#2093](https://github.com/atuinsh/atuin/issues/2093))
- *(ui/dotfiles)* Add vars ([#1989](https://github.com/atuinsh/atuin/issues/1989))
- Allow ignoring failed commands ([#1957](https://github.com/atuinsh/atuin/issues/1957))
- Show preview auto ([#1804](https://github.com/atuinsh/atuin/issues/1804))
- Add background daemon ([#2006](https://github.com/atuinsh/atuin/issues/2006))
- Support importing from replxx history files ([#2024](https://github.com/atuinsh/atuin/issues/2024))
- Support systemd socket activation for daemon ([#2039](https://github.com/atuinsh/atuin/issues/2039))
### Miscellaneous Tasks
- *(ci)* Don't run "Update Nix Deps" CI on forks ([#2070](https://github.com/atuinsh/atuin/issues/2070))
- *(codespell)* Ignore CODE_OF_CONDUCT ([#2044](https://github.com/atuinsh/atuin/issues/2044))
- *(install)* Log cargo and rustc version ([#2068](https://github.com/atuinsh/atuin/issues/2068))
- *(release)* V18.3.0-prerelease.1 ([#2090](https://github.com/atuinsh/atuin/issues/2090))
- Move crates into crates/ dir ([#1958](https://github.com/atuinsh/atuin/issues/1958))
- Fix atuin crate readme ([#1959](https://github.com/atuinsh/atuin/issues/1959))
- Add some more logging to handlers ([#1971](https://github.com/atuinsh/atuin/issues/1971))
- Add some more debug logs ([#1979](https://github.com/atuinsh/atuin/issues/1979))
- Clarify default config file ([#2026](https://github.com/atuinsh/atuin/issues/2026))
- Handle rate limited responses ([#2057](https://github.com/atuinsh/atuin/issues/2057))
- Add Systemd config for self-hosted server ([#1879](https://github.com/atuinsh/atuin/issues/1879))
- Switch to cargo dist for releases ([#2085](https://github.com/atuinsh/atuin/issues/2085))
- Update email, gitignore, tweak ui ([#2094](https://github.com/atuinsh/atuin/issues/2094))
- Show scope in changelog ([#2102](https://github.com/atuinsh/atuin/issues/2102))
### Performance
- *(nushell)* Use version.(major|minor|patch) if available ([#1963](https://github.com/atuinsh/atuin/issues/1963))
- Only open the database for commands if strictly required ([#2043](https://github.com/atuinsh/atuin/issues/2043))
### Refactor
- Preview_auto to use enum and different option ([#1991](https://github.com/atuinsh/atuin/issues/1991))
## 18.2.0
### Bug Fixes
- *(bash)* Do not use "return" to cancel initialization ([#1928](https://github.com/atuinsh/atuin/issues/1928))
- *(crate)* Add missing description ([#1861](https://github.com/atuinsh/atuin/issues/1861))
- *(doctor)* Detect preexec plugin using env ATUIN_PREEXEC_BACKEND ([#1856](https://github.com/atuinsh/atuin/issues/1856))
- *(install)* Install script echo ([#1899](https://github.com/atuinsh/atuin/issues/1899))
- *(nu)* Update atuin.nu to resolve 0.92 deprecation ([#1913](https://github.com/atuinsh/atuin/issues/1913))
- *(search)* Allow empty search ([#1866](https://github.com/atuinsh/atuin/issues/1866))
- *(search)* Case insensitive hostname filtering ([#1883](https://github.com/atuinsh/atuin/issues/1883))
- Pass search query in via env ([#1865](https://github.com/atuinsh/atuin/issues/1865))
- Pass search query in via env for *Nushell* ([#1874](https://github.com/atuinsh/atuin/issues/1874))
- Report non-decodable errors correctly ([#1915](https://github.com/atuinsh/atuin/issues/1915))
- Use spawn_blocking for file access during async context ([#1936](https://github.com/atuinsh/atuin/issues/1936))
### Documentation
- *(bash-preexec)* Describe the limitation of missing commands ([#1937](https://github.com/atuinsh/atuin/issues/1937))
- Add security contact ([#1867](https://github.com/atuinsh/atuin/issues/1867))
- Add install instructions for cave/exherbo linux in README.md ([#1927](https://github.com/atuinsh/atuin/issues/1927))
- Add missing cli help text ([#1945](https://github.com/atuinsh/atuin/issues/1945))
### Features
- *(bash/blesh)* Use _ble_exec_time_ata for duration even in bash < 5 ([#1940](https://github.com/atuinsh/atuin/issues/1940))
- *(dotfiles)* Add alias import ([#1938](https://github.com/atuinsh/atuin/issues/1938))
- *(gui)* Add base structure ([#1935](https://github.com/atuinsh/atuin/issues/1935))
- *(install)* Update install.sh to support KDE Neon ([#1908](https://github.com/atuinsh/atuin/issues/1908))
- *(search)* Process [C-h] and [C-?] as representations of backspace ([#1857](https://github.com/atuinsh/atuin/issues/1857))
- *(search)* Allow specifying search query as an env var ([#1863](https://github.com/atuinsh/atuin/issues/1863))
- *(search)* Add better search scoring ([#1885](https://github.com/atuinsh/atuin/issues/1885))
- *(server)* Check PG version before running migrations ([#1868](https://github.com/atuinsh/atuin/issues/1868))
- Add atuin prefix binding ([#1875](https://github.com/atuinsh/atuin/issues/1875))
- Sync v2 default for new installs ([#1914](https://github.com/atuinsh/atuin/issues/1914))
- Add 'ctrl-a a' to jump to beginning of line ([#1917](https://github.com/atuinsh/atuin/issues/1917))
- Prevents stderr from going to the screen ([#1933](https://github.com/atuinsh/atuin/issues/1933))
### Miscellaneous Tasks
- *(ci)* Add codespell support (config, workflow) and make it fix some typos ([#1916](https://github.com/atuinsh/atuin/issues/1916))
- *(gui)* Cargo update ([#1943](https://github.com/atuinsh/atuin/issues/1943))
- Add issue form ([#1871](https://github.com/atuinsh/atuin/issues/1871))
- Require atuin doctor in issue form ([#1872](https://github.com/atuinsh/atuin/issues/1872))
- Add section to issue form ([#1873](https://github.com/atuinsh/atuin/issues/1873))
### Performance
- *(dotfiles)* Cache aliases and read straight from file ([#1918](https://github.com/atuinsh/atuin/issues/1918))
## 18.1.0
### Bug Fixes
- *(bash)* Rework #1509 to recover from the preexec failure ([#1729](https://github.com/atuinsh/atuin/issues/1729))
- *(build)* Make atuin compile on non-win/mac/linux platforms ([#1825](https://github.com/atuinsh/atuin/issues/1825))
- *(client)* No panic on empty inspector ([#1768](https://github.com/atuinsh/atuin/issues/1768))
- *(doctor)* Use a different method to detect env vars ([#1819](https://github.com/atuinsh/atuin/issues/1819))
- *(dotfiles)* Use latest client ([#1859](https://github.com/atuinsh/atuin/issues/1859))
- *(import/zsh-histdb)* Missing or wrong fields ([#1740](https://github.com/atuinsh/atuin/issues/1740))
- *(nix)* Set meta.mainProgram in the package ([#1823](https://github.com/atuinsh/atuin/issues/1823))
- *(nushell)* Readd up-arrow keybinding, now with menu handling ([#1770](https://github.com/atuinsh/atuin/issues/1770))
- *(regex)* Disable regex error logs ([#1806](https://github.com/atuinsh/atuin/issues/1806))
- *(stats)* Enable multiple command stats to be shown using unicode_segmentation ([#1739](https://github.com/atuinsh/atuin/issues/1739))
- *(store-init)* Re-sync after running auto store init ([#1834](https://github.com/atuinsh/atuin/issues/1834))
- *(sync)* Check store length after sync, not before ([#1805](https://github.com/atuinsh/atuin/issues/1805))
- *(sync)* Record size limiter ([#1827](https://github.com/atuinsh/atuin/issues/1827))
- *(tz)* Attempt to fix timezone reading ([#1810](https://github.com/atuinsh/atuin/issues/1810))
- *(ui)* Don't preserve for empty space ([#1712](https://github.com/atuinsh/atuin/issues/1712))
- *(xonsh)* Add xonsh to auto import, respect $HISTFILE in xonsh import, and fix issue with up-arrow keybinding in xonsh ([#1711](https://github.com/atuinsh/atuin/issues/1711))
- Fish init ([#1725](https://github.com/atuinsh/atuin/issues/1725))
- Typo ([#1741](https://github.com/atuinsh/atuin/issues/1741))
- Check session file exists for status command ([#1756](https://github.com/atuinsh/atuin/issues/1756))
- Ensure sync time is saved for sync v2 ([#1758](https://github.com/atuinsh/atuin/issues/1758))
- Missing characters in preview ([#1803](https://github.com/atuinsh/atuin/issues/1803))
- Doctor shell wording ([#1858](https://github.com/atuinsh/atuin/issues/1858))
### Documentation
- Minor formatting updates to the default config.toml ([#1689](https://github.com/atuinsh/atuin/issues/1689))
- Update docker compose ([#1818](https://github.com/atuinsh/atuin/issues/1818))
- Use db name env variable also in uri ([#1840](https://github.com/atuinsh/atuin/issues/1840))
### Features
- *(client)* Add config option keys.scroll_exits ([#1744](https://github.com/atuinsh/atuin/issues/1744))
- *(dotfiles)* Add enable setting to dotfiles, disable by default ([#1829](https://github.com/atuinsh/atuin/issues/1829))
- *(nix)* Add update action ([#1779](https://github.com/atuinsh/atuin/issues/1779))
- *(nu)* Return early if history is disabled ([#1807](https://github.com/atuinsh/atuin/issues/1807))
- *(nushell)* Add nushell completion generation ([#1791](https://github.com/atuinsh/atuin/issues/1791))
- *(search)* Process Ctrl+m for kitty keyboard protocol ([#1720](https://github.com/atuinsh/atuin/issues/1720))
- *(stats)* Normalize formatting of default config, suggest nix ([#1764](https://github.com/atuinsh/atuin/issues/1764))
- *(stats)* Add linux sysadmin commands to common_subcommands ([#1784](https://github.com/atuinsh/atuin/issues/1784))
- *(ui)* Add config setting for showing tabs ([#1755](https://github.com/atuinsh/atuin/issues/1755))
- Use ATUIN_TEST_SQLITE_STORE_TIMEOUT to specify test timeout of SQLite store ([#1703](https://github.com/atuinsh/atuin/issues/1703))
- Add 'a', 'A', 'h', and 'l' bindings to vim-normal mode ([#1697](https://github.com/atuinsh/atuin/issues/1697))
- Add xonsh history import ([#1678](https://github.com/atuinsh/atuin/issues/1678))
- Add 'ignored_commands' option to stats ([#1722](https://github.com/atuinsh/atuin/issues/1722))
- Support syncing aliases ([#1721](https://github.com/atuinsh/atuin/issues/1721))
- Change fulltext to do multi substring match ([#1660](https://github.com/atuinsh/atuin/issues/1660))
- Add history prune subcommand ([#1743](https://github.com/atuinsh/atuin/issues/1743))
- Add alias feedback and list command ([#1747](https://github.com/atuinsh/atuin/issues/1747))
- Add PHP package manager "composer" to list of default common subcommands ([#1757](https://github.com/atuinsh/atuin/issues/1757))
- Add '/', '?', and 'I' bindings to vim-normal mode ([#1760](https://github.com/atuinsh/atuin/issues/1760))
- Add `CTRL+[` binding as `<Esc>` alias ([#1787](https://github.com/atuinsh/atuin/issues/1787))
- Add atuin doctor ([#1796](https://github.com/atuinsh/atuin/issues/1796))
- Add checks for common setup issues ([#1799](https://github.com/atuinsh/atuin/issues/1799))
- Support regex with r/.../ syntax ([#1745](https://github.com/atuinsh/atuin/issues/1745))
- Guard against ancient versions of bash where this does not work. ([#1794](https://github.com/atuinsh/atuin/issues/1794))
- Add automatic history store init ([#1831](https://github.com/atuinsh/atuin/issues/1831))
- Adds info command to show env vars and config files ([#1841](https://github.com/atuinsh/atuin/issues/1841))
### Miscellaneous Tasks
- *(ci)* Add cross-compile job for illumos ([#1830](https://github.com/atuinsh/atuin/issues/1830))
- *(ci)* Setup nextest ([#1848](https://github.com/atuinsh/atuin/issues/1848))
- Do not show history table stats when using records ([#1835](https://github.com/atuinsh/atuin/issues/1835))
### Performance
- Optimize history init-store ([#1691](https://github.com/atuinsh/atuin/issues/1691))
### Refactor
- *(alias)* Clarify operation result for working with aliases ([#1748](https://github.com/atuinsh/atuin/issues/1748))
- *(nushell)* Update `commandline` syntax, closes #1733 ([#1735](https://github.com/atuinsh/atuin/issues/1735))
- Rename atuin-config to atuin-dotfiles ([#1817](https://github.com/atuinsh/atuin/issues/1817))
## 18.0.1
### Bug Fixes
- Reorder the exit of enhanced keyboard mode ([#1694](https://github.com/atuinsh/atuin/issues/1694))
## 18.0.0
### Bug Fixes
- *(bash)* Avoid unexpected `atuin history start` for keybindings ([#1509](https://github.com/atuinsh/atuin/issues/1509))
- *(bash)* Prevent input to be interpreted as options for blesh auto-complete ([#1511](https://github.com/atuinsh/atuin/issues/1511))
- *(bash)* Work around custom IFS ([#1514](https://github.com/atuinsh/atuin/issues/1514))
- *(bash)* Fix and improve the keybinding to `up` ([#1515](https://github.com/atuinsh/atuin/issues/1515))
- *(bash)* Work around bash < 4 and introduce initialization guards ([#1533](https://github.com/atuinsh/atuin/issues/1533))
- *(bash)* Strip control chars generated by `\[\]` in PS1 with bash-preexec ([#1620](https://github.com/atuinsh/atuin/issues/1620))
- *(bash/preexec)* Erase the prompt last line before Bash renders it
- *(bash/preexec)* Erase the previous prompt before overwriting
- *(bash/preexec)* Support termcap names for tput ([#1670](https://github.com/atuinsh/atuin/issues/1670))
- *(docs)* Update repo url in CONTRIBUTING.md ([#1594](https://github.com/atuinsh/atuin/issues/1594))
- *(fish)* Integration on older fishes ([#1563](https://github.com/atuinsh/atuin/issues/1563))
- *(perm)* Set umask 077 ([#1554](https://github.com/atuinsh/atuin/issues/1554))
- *(search)* Fix invisible tab title ([#1560](https://github.com/atuinsh/atuin/issues/1560))
- *(shell)* Fix incorrect timing of child shells ([#1510](https://github.com/atuinsh/atuin/issues/1510))
- *(sync)* Save sync time when it starts, not ends ([#1573](https://github.com/atuinsh/atuin/issues/1573))
- *(tests)* Add Settings::utc() for utc settings ([#1677](https://github.com/atuinsh/atuin/issues/1677))
- *(tui)* Dedupe was removing history ([#1610](https://github.com/atuinsh/atuin/issues/1610))
- *(windows)* Disables unix specific stuff for windows ([#1557](https://github.com/atuinsh/atuin/issues/1557))
- Prevent input to be interpreted as options for zsh autosuggestions ([#1506](https://github.com/atuinsh/atuin/issues/1506))
- Disable musl deb building ([#1525](https://github.com/atuinsh/atuin/issues/1525))
- Shorten text, use ctrl-o for inspector ([#1561](https://github.com/atuinsh/atuin/issues/1561))
- Print literal control characters to non terminals ([#1586](https://github.com/atuinsh/atuin/issues/1586))
- Escape control characters in command preview ([#1588](https://github.com/atuinsh/atuin/issues/1588))
- Use existing db querying for history list ([#1589](https://github.com/atuinsh/atuin/issues/1589))
- Add acquire timeout to sqlite database connection ([#1590](https://github.com/atuinsh/atuin/issues/1590))
- Only escape control characters when writing to terminal ([#1593](https://github.com/atuinsh/atuin/issues/1593))
- Check for format errors when printing history ([#1623](https://github.com/atuinsh/atuin/issues/1623))
- Skip padding time if it will overflow the allowed prefix length ([#1630](https://github.com/atuinsh/atuin/issues/1630))
- Never overwrite the key ([#1657](https://github.com/atuinsh/atuin/issues/1657))
- Set durability for sqlite to recommended settings ([#1667](https://github.com/atuinsh/atuin/issues/1667))
- Correct download list for incremental builds ([#1672](https://github.com/atuinsh/atuin/issues/1672))
### Documentation
- *(README)* Clarify prerequisites for Bash ([#1686](https://github.com/atuinsh/atuin/issues/1686))
- *(readme)* Add repology badge ([#1494](https://github.com/atuinsh/atuin/issues/1494))
- Add forum link to contributing ([#1498](https://github.com/atuinsh/atuin/issues/1498))
- Refer to image with multi-arch support ([#1513](https://github.com/atuinsh/atuin/issues/1513))
- Remove activity graph
- Fix `Destination file already exists` in Nushell ([#1530](https://github.com/atuinsh/atuin/issues/1530))
- Clarify enter/tab usage ([#1538](https://github.com/atuinsh/atuin/issues/1538))
- Improve style ([#1537](https://github.com/atuinsh/atuin/issues/1537))
- Remove old docusaurus ([#1581](https://github.com/atuinsh/atuin/issues/1581))
- Mention environment variables for custom paths ([#1614](https://github.com/atuinsh/atuin/issues/1614))
- Create pull_request_template.md ([#1632](https://github.com/atuinsh/atuin/issues/1632))
- Update CONTRIBUTING.md ([#1633](https://github.com/atuinsh/atuin/issues/1633))
### Features
- *(bash)* Support high-resolution timing even without ble.sh ([#1534](https://github.com/atuinsh/atuin/issues/1534))
- *(search)* Introduce keymap-dependent vim-mode ([#1570](https://github.com/atuinsh/atuin/issues/1570))
- *(search)* Make cursor style configurable ([#1595](https://github.com/atuinsh/atuin/issues/1595))
- *(shell)* Bind the Atuin search to "/" in vi-normal mode ([#1629](https://github.com/atuinsh/atuin/issues/1629))
- **BREAKING**: bind the Atuin search to "/" in vi-normal mode ([#1629](https://github.com/atuinsh/atuin/issues/1629))
- *(ui)* Add redraw ([#1519](https://github.com/atuinsh/atuin/issues/1519))
- *(ui)* Vim mode ([#1553](https://github.com/atuinsh/atuin/issues/1553))
- *(ui)* When in vim-normal mode apply an alternative highlighting to the selected line ([#1574](https://github.com/atuinsh/atuin/issues/1574))
- *(zsh)* Update widget names ([#1631](https://github.com/atuinsh/atuin/issues/1631))
- Enable enhanced keyboard mode ([#1505](https://github.com/atuinsh/atuin/issues/1505))
- Rework record sync for improved reliability ([#1478](https://github.com/atuinsh/atuin/issues/1478))
- Include atuin login in secret patterns ([#1518](https://github.com/atuinsh/atuin/issues/1518))
- Make it clear what you are registering for ([#1523](https://github.com/atuinsh/atuin/issues/1523))
- Add extended help ([#1540](https://github.com/atuinsh/atuin/issues/1540))
- Add interactive command inspector ([#1296](https://github.com/atuinsh/atuin/issues/1296))
- Add better error handling for sync ([#1572](https://github.com/atuinsh/atuin/issues/1572))
- Add history rebuild ([#1575](https://github.com/atuinsh/atuin/issues/1575))
- Make deleting from the UI work with record store sync ([#1580](https://github.com/atuinsh/atuin/issues/1580))
- Add metrics counter for records downloaded ([#1584](https://github.com/atuinsh/atuin/issues/1584))
- Make store init idempotent ([#1609](https://github.com/atuinsh/atuin/issues/1609))
- Don't stop with invalid key ([#1612](https://github.com/atuinsh/atuin/issues/1612))
- Add registered and deleted metrics ([#1622](https://github.com/atuinsh/atuin/issues/1622))
- Make history list format configurable ([#1638](https://github.com/atuinsh/atuin/issues/1638))
- Add change-password command & support on server ([#1615](https://github.com/atuinsh/atuin/issues/1615))
- Automatically init history store when record sync is enabled ([#1634](https://github.com/atuinsh/atuin/issues/1634))
- Add store push ([#1649](https://github.com/atuinsh/atuin/issues/1649))
- Reencrypt/rekey local store ([#1662](https://github.com/atuinsh/atuin/issues/1662))
- Add prefers_reduced_motion flag ([#1645](https://github.com/atuinsh/atuin/issues/1645))
- Add verify command to local store
- Add store purge command
- Failure to decrypt history = failure to sync
- Add `store push --force`
- Add `store pull`
- Disable auto record store init ([#1671](https://github.com/atuinsh/atuin/issues/1671))
- Add progress bars to sync and store init ([#1684](https://github.com/atuinsh/atuin/issues/1684))
### Miscellaneous Tasks
- *(ci)* Use github m1 for release builds ([#1658](https://github.com/atuinsh/atuin/issues/1658))
- *(ci)* Re-enable test cache, add separate check step ([#1663](https://github.com/atuinsh/atuin/issues/1663))
- *(ci)* Run rust build/test/check on 3 platforms ([#1675](https://github.com/atuinsh/atuin/issues/1675))
- Remove the teapot response ([#1496](https://github.com/atuinsh/atuin/issues/1496))
- Schema cleanup ([#1522](https://github.com/atuinsh/atuin/issues/1522))
- Update funding ([#1543](https://github.com/atuinsh/atuin/issues/1543))
- Make clipboard dep optional as a feature ([#1558](https://github.com/atuinsh/atuin/issues/1558))
- Add feature to allow always disable check update ([#1628](https://github.com/atuinsh/atuin/issues/1628))
- Use resolver 2, update editions + cargo ([#1635](https://github.com/atuinsh/atuin/issues/1635))
- Disable nix tests ([#1646](https://github.com/atuinsh/atuin/issues/1646))
- Set ATUIN_ variables for development in devshell ([#1653](https://github.com/atuinsh/atuin/issues/1653))
### Refactor
- *(search)* Refactor vim mode ([#1559](https://github.com/atuinsh/atuin/issues/1559))
- *(search)* Refactor handling of key inputs ([#1606](https://github.com/atuinsh/atuin/issues/1606))
- *(shell)* Refactor and localize `HISTORY => __atuin_output` ([#1535](https://github.com/atuinsh/atuin/issues/1535))
- Use enum instead of magic numbers ([#1499](https://github.com/atuinsh/atuin/issues/1499))
- String -> HistoryId ([#1512](https://github.com/atuinsh/atuin/issues/1512))
### Styling
- *(bash)* Use consistent coding style ([#1528](https://github.com/atuinsh/atuin/issues/1528))
### Testing
- Add multi-user integration tests ([#1648](https://github.com/atuinsh/atuin/issues/1648))
### Stats
- Misc improvements ([#1613](https://github.com/atuinsh/atuin/issues/1613))
## 17.2.1
### Bug Fixes
- *(server)* Typo with default config ([#1493](https://github.com/atuinsh/atuin/issues/1493))
## 17.2.0
### Bug Fixes
- *(bash)* Fix loss of the last output line with enter_accept ([#1463](https://github.com/atuinsh/atuin/issues/1463))
- *(bash)* Improve the support for `enter_accept` with `ble.sh` ([#1465](https://github.com/atuinsh/atuin/issues/1465))
- *(bash)* Fix small issues of `enter_accept` for the plain Bash ([#1467](https://github.com/atuinsh/atuin/issues/1467))
- *(bash)* Fix error by the use of ${PS1@P} in bash < 4.4 ([#1488](https://github.com/atuinsh/atuin/issues/1488))
- *(bash,zsh)* Fix quirks on search cancel ([#1483](https://github.com/atuinsh/atuin/issues/1483))
- *(clippy)* Ignore struct_field_names ([#1466](https://github.com/atuinsh/atuin/issues/1466))
- *(docs)* Fix typo ([#1439](https://github.com/atuinsh/atuin/issues/1439))
- *(docs)* Discord link expired
- *(history)* Disallow deletion if the '--limit' flag is present ([#1436](https://github.com/atuinsh/atuin/issues/1436))
- *(import/zsh)* Zsh use a special format to escape some characters ([#1490](https://github.com/atuinsh/atuin/issues/1490))
- *(install)* Discord broken link
- *(shell)* Respect ZSH's $ZDOTDIR environment variable ([#1441](https://github.com/atuinsh/atuin/issues/1441))
- *(stats)* Don't require all fields under [stats] ([#1437](https://github.com/atuinsh/atuin/issues/1437))
- *(stats)* Time now_local not working
- *(zsh)* Zsh_autosuggest_strategy for no-unset environment ([#1486](https://github.com/atuinsh/atuin/issues/1486))
### Documentation
- *(readme)* Add actuated linkback
- *(readme)* Fix light/dark mode logo
- *(readme)* Use picture element for logo
- Add link to forum
- Align setup links in docs and readme ([#1446](https://github.com/atuinsh/atuin/issues/1446))
- Add Void Linux install instruction ([#1445](https://github.com/atuinsh/atuin/issues/1445))
- Add fish install script ([#1447](https://github.com/atuinsh/atuin/issues/1447))
- Correct link
- Add docs for zsh-autosuggestion integration ([#1480](https://github.com/atuinsh/atuin/issues/1480))
- Remove stray character from README
- Update logo ([#1481](https://github.com/atuinsh/atuin/issues/1481))
### Features
- *(bash)* Provide auto-complete source for ble.sh ([#1487](https://github.com/atuinsh/atuin/issues/1487))
- *(shell)* Support high-resolution duration if available ([#1484](https://github.com/atuinsh/atuin/issues/1484))
- Add semver checking to client requests ([#1456](https://github.com/atuinsh/atuin/issues/1456))
- Add TLS to atuin-server ([#1457](https://github.com/atuinsh/atuin/issues/1457))
- Integrate with zsh-autosuggestions ([#1479](https://github.com/atuinsh/atuin/issues/1479))
### Miscellaneous Tasks
- *(repo)* Remove issue config ([#1433](https://github.com/atuinsh/atuin/issues/1433))
- Remove issue template ([#1444](https://github.com/atuinsh/atuin/issues/1444))
### Refactor
- *(bash)* Factorize `__atuin_accept_line` ([#1476](https://github.com/atuinsh/atuin/issues/1476))
- *(bash)* Refactor and optimize `__atuin_accept_line` ([#1482](https://github.com/atuinsh/atuin/issues/1482))
## 17.1.0
### Bug Fixes
- *(fish)* Clean up the fish script options ([#1370](https://github.com/atuinsh/atuin/issues/1370))
- *(fish)* Use fish builtins for `enter_accept` ([#1373](https://github.com/atuinsh/atuin/issues/1373))
- *(fish)* Accept multiline commands ([#1418](https://github.com/atuinsh/atuin/issues/1418))
- *(nix)* Add Appkit to the package build ([#1358](https://github.com/atuinsh/atuin/issues/1358))
- *(zsh)* Bind in the most popular modes ([#1360](https://github.com/atuinsh/atuin/issues/1360))
- *(zsh)* Only trigger up-arrow on first line ([#1359](https://github.com/atuinsh/atuin/issues/1359))
- Initial list of history in workspace mode ([#1356](https://github.com/atuinsh/atuin/issues/1356))
- Make `atuin account delete` void session + key ([#1393](https://github.com/atuinsh/atuin/issues/1393))
- New clippy lints ([#1395](https://github.com/atuinsh/atuin/issues/1395))
- Reenable enter_accept for bash ([#1408](https://github.com/atuinsh/atuin/issues/1408))
- Respect ZSH's $ZDOTDIR environment variable ([#942](https://github.com/atuinsh/atuin/issues/942))
### Documentation
- Update sync.md ([#1409](https://github.com/atuinsh/atuin/issues/1409))
- Update Arch Linux package URL in advanced-install.md ([#1407](https://github.com/atuinsh/atuin/issues/1407))
- New stats config ([#1412](https://github.com/atuinsh/atuin/issues/1412))
### Features
- *(nix)* Add a nixpkgs overlay ([#1357](https://github.com/atuinsh/atuin/issues/1357))
- Add metrics server and http metrics ([#1394](https://github.com/atuinsh/atuin/issues/1394))
- Add some metrics related to Atuin as an app ([#1399](https://github.com/atuinsh/atuin/issues/1399))
- Allow configuring stats prefix ([#1411](https://github.com/atuinsh/atuin/issues/1411))
- Allow spaces in stats prefixes ([#1414](https://github.com/atuinsh/atuin/issues/1414))
### Miscellaneous Tasks
- *(readme)* Add contributor image to README ([#1430](https://github.com/atuinsh/atuin/issues/1430))
- Update to sqlx 0.7.3 ([#1416](https://github.com/atuinsh/atuin/issues/1416))
- `cargo update` ([#1419](https://github.com/atuinsh/atuin/issues/1419))
- Update rusty_paseto and rusty_paserk ([#1420](https://github.com/atuinsh/atuin/issues/1420))
- Run dependabot weekly, not daily ([#1423](https://github.com/atuinsh/atuin/issues/1423))
- Don't group deps ([#1424](https://github.com/atuinsh/atuin/issues/1424))
- Setup git cliff ([#1431](https://github.com/atuinsh/atuin/issues/1431))
## 17.0.1
### Bug Fixes
- *(bash)* Improve output of `enter_accept` ([#1342](https://github.com/atuinsh/atuin/issues/1342))
- *(enter_accept)* Clear old cmd snippet ([#1350](https://github.com/atuinsh/atuin/issues/1350))
- *(fish)* Improve output for `enter_accept` ([#1341](https://github.com/atuinsh/atuin/issues/1341))
## 17.0.0
### Bug Fixes
- *(1220)* Workspace Filtermode not handled in skim engine ([#1273](https://github.com/atuinsh/atuin/issues/1273))
- *(nu)* Disable the up-arrow keybinding for Nushell ([#1329](https://github.com/atuinsh/atuin/issues/1329))
- *(nushell)* Ignore stderr messages ([#1320](https://github.com/atuinsh/atuin/issues/1320))
- *(ubuntu/arm*)* Detect non amd64 ubuntu and handle ([#1131](https://github.com/atuinsh/atuin/issues/1131))
### Documentation
- Update `workspace` config key to `workspaces` ([#1174](https://github.com/atuinsh/atuin/issues/1174))
- Document the available format options of History list command ([#1234](https://github.com/atuinsh/atuin/issues/1234))
### Features
- *(installer)* Try installing via paru for the AUR ([#1262](https://github.com/atuinsh/atuin/issues/1262))
- *(keyup)* Configure SearchMode for KeyUp invocation #1216 ([#1224](https://github.com/atuinsh/atuin/issues/1224))
- Mouse selection support ([#1209](https://github.com/atuinsh/atuin/issues/1209))
- Copy to clipboard ([#1249](https://github.com/atuinsh/atuin/issues/1249))
### Refactor
- Duplications reduced in order to align implementations of reading history files ([#1247](https://github.com/atuinsh/atuin/issues/1247))
### Config.md
- Invert mode detailed options ([#1225](https://github.com/atuinsh/atuin/issues/1225))
## 16.0.0
### Bug Fixes
- *(docs)* List all presently documented commands ([#1140](https://github.com/atuinsh/atuin/issues/1140))
- *(docs)* Correct command overview paths ([#1145](https://github.com/atuinsh/atuin/issues/1145))
- *(server)* Teapot is a cup of coffee ([#1137](https://github.com/atuinsh/atuin/issues/1137))
- Adjust broken link to supported shells ([#1013](https://github.com/atuinsh/atuin/issues/1013))
- Fixes unix specific impl of shutdown_signal ([#1061](https://github.com/atuinsh/atuin/issues/1061))
- Nushell empty hooks ([#1138](https://github.com/atuinsh/atuin/issues/1138))
### Features
- Do not allow empty passwords durring account creation ([#1029](https://github.com/atuinsh/atuin/issues/1029))
### Skim
- Fix filtering aggregates ([#1114](https://github.com/atuinsh/atuin/issues/1114))
## 15.0.0
### Documentation
- Fix broken links in README.md ([#920](https://github.com/atuinsh/atuin/issues/920))
- Fix "From source" `cd` command ([#937](https://github.com/atuinsh/atuin/issues/937))
### Features
- Add delete account option (attempt 2) ([#980](https://github.com/atuinsh/atuin/issues/980))
### Miscellaneous Tasks
- Uuhhhhhh crypto lol ([#805](https://github.com/atuinsh/atuin/issues/805))
- Fix participle "be ran" -> "be run" ([#939](https://github.com/atuinsh/atuin/issues/939))
### Cwd_filter
- Much like history_filter, only it applies to cwd ([#904](https://github.com/atuinsh/atuin/issues/904))
## 14.0.0
### Bug Fixes
- *(client)* Always read session_path from settings ([#757](https://github.com/atuinsh/atuin/issues/757))
- *(installer)* Use case-insensitive comparison ([#776](https://github.com/atuinsh/atuin/issues/776))
- Many wins were broken :memo: ([#789](https://github.com/atuinsh/atuin/issues/789))
- Paste into terminal after switching modes ([#793](https://github.com/atuinsh/atuin/issues/793))
- Record negative exit codes ([#821](https://github.com/atuinsh/atuin/issues/821))
- Allow nix package to fetch dependencies from git ([#832](https://github.com/atuinsh/atuin/issues/832))
### Documentation
- *(README)* Fix activity graph link ([#753](https://github.com/atuinsh/atuin/issues/753))
### Features
- Add common default keybindings ([#719](https://github.com/atuinsh/atuin/issues/719))
- Add an inline view mode ([#648](https://github.com/atuinsh/atuin/issues/648))
- Add *Nushell* support ([#788](https://github.com/atuinsh/atuin/issues/788))
- Add github action to test the nix builds ([#833](https://github.com/atuinsh/atuin/issues/833))
### Miscellaneous Tasks
- Remove tui vendoring ([#804](https://github.com/atuinsh/atuin/issues/804))
- Use fork of skim ([#803](https://github.com/atuinsh/atuin/issues/803))
### Nix
- Add flake-compat ([#743](https://github.com/atuinsh/atuin/issues/743))
## 13.0.0
### Documentation
- *(README)* Add static activity graph example ([#680](https://github.com/atuinsh/atuin/issues/680))
- Remove human short flag from docs, duplicate of help -h ([#663](https://github.com/atuinsh/atuin/issues/663))
- Fix typo in zh-CN/README.md ([#666](https://github.com/atuinsh/atuin/issues/666))
### Features
- *(history)* Add new flag to allow custom output format ([#662](https://github.com/atuinsh/atuin/issues/662))
### Fish
- Fix `atuin init` for the fish shell ([#699](https://github.com/atuinsh/atuin/issues/699))
### Install.sh
- Fallback to using cargo ([#639](https://github.com/atuinsh/atuin/issues/639))
## 12.0.0
### Documentation
- Add more details about date parsing in the stats command ([#579](https://github.com/atuinsh/atuin/issues/579))
## 0.10.0
### Miscellaneous Tasks
- Allow specifiying the limited of returned entries ([#364](https://github.com/atuinsh/atuin/issues/364))
## 0.9.0
### README
- Add MacPorts installation instructions ([#302](https://github.com/atuinsh/atuin/issues/302))
## 0.8.1
### Bug Fixes
- Get install.sh working on UbuntuWSL ([#260](https://github.com/atuinsh/atuin/issues/260))
## 0.8.0
### Bug Fixes
- Resolve some issues with install.sh ([#188](https://github.com/atuinsh/atuin/issues/188))
### Features
- Login/register no longer blocking ([#216](https://github.com/atuinsh/atuin/issues/216))
## 0.7.2
### Bug Fixes
- Dockerfile with correct glibc ([#198](https://github.com/atuinsh/atuin/issues/198))
### Features
- Allow input of credentials from stdin ([#185](https://github.com/atuinsh/atuin/issues/185))
### Miscellaneous Tasks
- Some new linting ([#201](https://github.com/atuinsh/atuin/issues/201))
- Supply pre-build docker image ([#199](https://github.com/atuinsh/atuin/issues/199))
- Add more eyre contexts ([#200](https://github.com/atuinsh/atuin/issues/200))
- Improve build times ([#213](https://github.com/atuinsh/atuin/issues/213))
## 0.7.1
### Features
- Build individual crates ([#109](https://github.com/atuinsh/atuin/issues/109))
## 0.6.3
### Bug Fixes
- Help text
### Features
- Use directories project data dir
### Miscellaneous Tasks
- Use structopt wrapper instead of building clap by hand
<!-- generated by git-cliff -->
================================================
FILE: CODE_OF_CONDUCT.md
================================================
# Contributor Covenant Code of Conduct
## Our Pledge
We as members, contributors, and leaders pledge to make participation in our
community a harassment-free experience for everyone, regardless of age, body
size, visible or invisible disability, ethnicity, sex characteristics, gender
identity and expression, level of experience, education, socio-economic status,
nationality, personal appearance, race, religion, or sexual identity
and orientation.
We pledge to act and interact in ways that contribute to an open, welcoming,
diverse, inclusive, and healthy community.
## Our Standards
Examples of behavior that contributes to a positive environment for our
community include:
* Demonstrating empathy and kindness toward other people
* Being respectful of differing opinions, viewpoints, and experiences
* Giving and gracefully accepting constructive feedback
* Accepting responsibility and apologizing to those affected by our mistakes,
and learning from the experience
* Focusing on what is best not just for us as individuals, but for the
overall community
Examples of unacceptable behavior include:
* The use of sexualized language or imagery, and sexual attention or
advances of any kind
* Trolling, insulting or derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or email
address, without their explicit permission
* Other conduct which could reasonably be considered inappropriate in a
professional setting
## Enforcement Responsibilities
Community leaders are responsible for clarifying and enforcing our standards of
acceptable behavior and will take appropriate and fair corrective action in
response to any behavior that they deem inappropriate, threatening, offensive,
or harmful.
Community leaders have the right and responsibility to remove, edit, or reject
comments, commits, code, wiki edits, issues, and other contributions that are
not aligned to this Code of Conduct, and will communicate reasons for moderation
decisions when appropriate.
## Scope
This Code of Conduct applies within all community spaces, and also applies when
an individual is officially representing the community in public spaces.
Examples of representing our community include using an official e-mail address,
posting via an official social media account, or acting as an appointed
representative at an online or offline event.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported to the community leaders responsible for enforcement at
ellie@elliehuxtable.com.
All complaints will be reviewed and investigated promptly and fairly.
All community leaders are obligated to respect the privacy and security of the
reporter of any incident.
## Enforcement Guidelines
Community leaders will follow these Community Impact Guidelines in determining
the consequences for any action they deem in violation of this Code of Conduct:
### 1. Correction
**Community Impact**: Use of inappropriate language or other behavior deemed
unprofessional or unwelcome in the community.
**Consequence**: A private, written warning from community leaders, providing
clarity around the nature of the violation and an explanation of why the
behavior was inappropriate. A public apology may be requested.
### 2. Warning
**Community Impact**: A violation through a single incident or series
of actions.
**Consequence**: A warning with consequences for continued behavior. No
interaction with the people involved, including unsolicited interaction with
those enforcing the Code of Conduct, for a specified period of time. This
includes avoiding interactions in community spaces as well as external channels
like social media. Violating these terms may lead to a temporary or
permanent ban.
### 3. Temporary Ban
**Community Impact**: A serious violation of community standards, including
sustained inappropriate behavior.
**Consequence**: A temporary ban from any sort of interaction or public
communication with the community for a specified period of time. No public or
private interaction with the people involved, including unsolicited interaction
with those enforcing the Code of Conduct, is allowed during this period.
Violating these terms may lead to a permanent ban.
### 4. Permanent Ban
**Community Impact**: Demonstrating a pattern of violation of community
standards, including sustained inappropriate behavior, harassment of an
individual, or aggression toward or disparagement of classes of individuals.
**Consequence**: A permanent ban from any sort of public interaction within
the community.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
version 2.0, available at
https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.
Community Impact Guidelines were inspired by [Mozilla's code of conduct
enforcement ladder](https://github.com/mozilla/diversity).
[homepage]: https://www.contributor-covenant.org
For answers to common questions about this code of conduct, see the FAQ at
https://www.contributor-covenant.org/faq. Translations are available at
https://www.contributor-covenant.org/translations.
================================================
FILE: CONTRIBUTING.md
================================================
# Contributing
Thank you so much for considering contributing to Atuin! We really appreciate it <3
Development dependencies
1. A rust toolchain ([rustup](https://rustup.rs) recommended)
We commit to supporting the latest stable version of Rust - nothing more, nothing less, no nightly.
Before working on anything, we suggest taking a copy of your Atuin data directory (`~/.local/share/atuin` on most \*nix platforms). If anything goes wrong, you can always restore it!
While data directory backups are always a good idea, you can instruct Atuin to use custom path using the following environment variables:
```shell
export ATUIN_RECORD_STORE_PATH=/tmp/atuin_records.db
export ATUIN_DB_PATH=/tmp/atuin_dev.db
export ATUIN_KV__DB_PATH=/tmp/atuin_kv.db
export ATUIN_SCRIPTS__DB_PATH=/tmp/atuin_scripts.db
```
It is also recommended to update your `$PATH` so that the pre-exec scripts would use the locally built version:
```shell
export PATH="./target/release:$PATH"
```
If you'd like to load a different configuration file, set `ATUIN_CONFIG_DIR` to a folder that contains your `config.toml` file:
```shell
export ATUIN_CONFIG_DIR=/tmp/atuin-config/
```
These variable exports can be added in a local `.envrc` file, read by [direnv](https://direnv.net/).
## PRs
It can speed up the review cycle if you consent to maintainers pushing to your branch. This will only be in the case of small fixes or adjustments, and not anything large. If you feel OK with this, please check the box on the template!
## What to work on?
Any issues labeled "bug" or "help wanted" would be fantastic, just drop a comment and feel free to ask for help!
If there's anything you want to work on that isn't already an issue, either open a feature request or get in touch on the [forum](https://forum.atuin.sh)/Discord.
## Setup
```
git clone https://github.com/atuinsh/atuin
cd atuin
cargo build
```
## Running
When iterating on a feature, it's useful to use `cargo run`
For example, if working on a search feature
```
cargo run -- search --a-new-flag
```
While iterating on the server, I find it helpful to run a new user on my system, with `sync_server` set to be `localhost`.
## Tests
Our test coverage is currently not the best, but we are working on it! Generally tests live in the file next to the functionality they are testing, and are executed just with `cargo test`.
## Logging and Debugging
### Log Files
Atuin writes logs to `~/.atuin/logs` unless configured otherwise. Log files are rotated daily and retained for 4 days by default:
- `search.log.*` - Interactive search session logs
- `daemon.log.*` - Background daemon logs
### Log Levels
You can set the `ATUIN_LOG` environment variable to override log verbosity from the config file:
```shell
ATUIN_LOG=debug atuin search # Enable debug logging
ATUIN_LOG=trace atuin search # Enable trace logging (very verbose)
```
### Span Timing (Performance Profiling)
For performance analysis, you can capture detailed span timing data as JSON:
```shell
ATUIN_SPAN=spans.json atuin search
```
This creates a JSON file with timing information for each instrumented span, including:
- `time.busy` - Time actively executing code
- `time.idle` - Time awaiting async operations (I/O, child tasks)
The `scripts/span-table.ts` script analyzes these logs:
```shell
# Summary view - shows all spans with timing stats
bun scripts/span-table.ts spans.json
# Detail view - shows individual calls for a specific span
bun scripts/span-table.ts spans.json --detail daemon_search
# Filter to specific spans
bun scripts/span-table.ts spans.json --filter "search|hydrate"
```
This is useful for comparing performance between different search implementations or identifying bottlenecks.
## Migrations
Be careful creating database migrations - once your database has migrated ahead of current stable, there is no going back
### Stickers
We try to ship anyone contributing to Atuin a sticker! Only contributors get a shiny one. Fill out [this form](https://noteforms.com/forms/contributors-stickers) if you'd like one.
================================================
FILE: CONTRIBUTORS
================================================
0x4A6F <0x4A6F@users.noreply.github.com>
Aleks Bunin <sashkab@users.noreply.github.com>
Alex Hamilton <1622250+Aehmlo@users.noreply.github.com>
Alexandre GV. <contact@alexandregv.fr>
Aloxaf <bailong104@gmail.com>
Alpha Chen <alpha@kejadlen.dev>
Amos Bird <amosbird@gmail.com>
Anderson <141751473+digital-cuttlefish@users.noreply.github.com>
Andrew Aylett <andrew@aylett.co.uk>
Andrew Lee <32912555+candrewlee14@users.noreply.github.com>
Anish Pallati <anishp@duck.com>
Austin Schey <aschey13@gmail.com>
avinassh <640792+avinassh@users.noreply.github.com>
Azzam S.A <17734314+azzamsa@users.noreply.github.com>
b3nj5m1n <47924309+b3nj5m1n@users.noreply.github.com>
Baptiste <32563450+BapRx@users.noreply.github.com>
Ben J <bdavjones@gmail.com>
Benjamin Vergnaud <9599845+bvergnaud@users.noreply.github.com>
Benjamin Weinstein-Raun <b@w-r.me>
Blair Noctis <4474501+nc7s@users.noreply.github.com>
Brad Robel-Forrest <brad@bitpony.com>
Braelyn Boynton <bboynton97@gmail.com>
Brian Kung <2836167+briankung@users.noreply.github.com>
Bruce Huang <helbingxxx@gmail.com>
c-14 <git@c-14.de>
Caleb Maclennan <caleb@alerque.com>
Ch. (Chanwhi Choi) <ccwpc@hanmail.net>
Chandra Kiran G <chandra.kiran@cai-solutions.com>
chitao1234 <1139954766@qq.com>
Chris Rose <offline@offby1.net>
Conrad Ludgate <conradludgate@gmail.com>
CosmicHorror <LovecraftianHorror@pm.me>
Cristian Le <git@lecris.dev>
Cristian Le <github@lecris.me>
CULT PONY <67918945+cultpony@users.noreply.github.com>
cyqsimon <28627918+cyqsimon@users.noreply.github.com>
Dagan McGregor <d.mcgregor@gns.cri.nz>
Daniel <daniel.hub@outlook.de>
Daniel Carosone <daniel.carosone@gmail.com>
DaniPopes <57450786+DaniPopes@users.noreply.github.com>
David <drmorr@appliedcomputing.io>
David <drmorr@evokewonder.com>
David Chocholatý <chocholaty.david@protonmail.com>
David Jack Wange Olrik <david@olrik.dk>
David Legrand <1110600+davlgd@users.noreply.github.com>
Dennis Trautwein <git@dtrautwein.eu>
dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Devin Buhl <onedr0p@users.noreply.github.com>
Dhruv Thakur <13575379+dhth@users.noreply.github.com>
Diego Carrasco Gubernatis <557703+dacog@users.noreply.github.com>
Dieter Eickstaedt <eickstaedt@deicon.de>
Dom Rodriguez <shymega@users.noreply.github.com>
Dongxu Wang <dongxu@apache.org>
DS/Charlie <82801887+ds-cbo@users.noreply.github.com>
Ed Ive <ed.ivve@gmail.com>
Edward Loveall <edward@edwardloveall.com>
Ellie Huxtable <ellie@atuin.sh>
Emanuele Panzeri <thepanz@gmail.com>
Eric Crosson <EricCrosson@users.noreply.github.com>
Eric Hodel <drbrain@segment7.net>
Eric Long <i@hack3r.moe>
Eric Ripa <eric@ripa.io>
Erwin Kroon <123574+ekroon@users.noreply.github.com>
eth3lbert <eth3lbert+dev@gmail.com>
Ethan Brierley <ethanboxx@gmail.com>
Evan McBeth <64177332+AtomicRobotMan0101@users.noreply.github.com>
Evan Purkhiser <evanpurkhiser@gmail.com>
Farid Zakaria <farid.m.zakaria@gmail.com>
Felix Yan <felixonmars@archlinux.org>
Frank Hamand <frankhamand@gmail.com>
frukto <fruktopus@gmail.com>
Gokul <appu.yess@gmail.com>
Hamza Hamud <53880692+hhamud@users.noreply.github.com>
Helmut K. C. Tessarek <tessarek@evermeet.cx>
Herby Gillot <herby.gillot@gmail.com>
Hesam Pakdaman <14890379+hesampakdaman@users.noreply.github.com>
Hilmar Wiegand <me@hwgnd.de>
Hunter Casten <41604962+enchantednatures@users.noreply.github.com>
Ian Manske <ian.manske@pm.me>
Ian Smith <iansmith@honeycomb.io>
Ian Smith <ismith@mit.edu>
Ilkin Bayramli <43158991+ibayramli@users.noreply.github.com>
Ivan Toriya <43750521+ivan-toriya@users.noreply.github.com>
J. Emiliano Deustua <edeustua@gmail.com>
Jakob Schrettenbrunner <dev@schrej.net>
Jakub Jirutka <jakub@jirutka.cz>
Jakub Panek <me@panekj.dev>
James Trew <66286082+jamestrew@users.noreply.github.com>
Jamie Quigley <jamie@quigley.xyz>
Jan Larres <jan@majutsushi.net>
Jannik <32144358+mozzieongit@users.noreply.github.com>
Jannik <jannik.peters@posteo.de>
Jax Young <jaxvanyang@gmail.com>
jean-santos <ewqjean@gmail.com>
jean-santos <jeanpnsantos@gmail.com>
Jeff Gould <JRGould@gmail.com>
Jeremy Cline <github@declined.dev>
Jeremy Cline <jeremy@jcline.org>
Jerome Ducret <jdiphone34@gmail.com>
jfmontanaro <jfmonty2@gmail.com>
Jinn Koriech <jinnko@users.noreply.github.com>
Jinna Kiisuo <jinna@nocturnal.fi>
Joe Ardent <nebkor@users.noreply.github.com>
Johannes Baiter <johannes.baiter@gmail.com>
Josef Friedrich <josef@friedrich.rocks>
JT <547158+jntrnr@users.noreply.github.com>
Julien P <julien@caffeine.lu>
Justin Su <injustsu@gmail.com>
János Illés <ijanos@gmail.com>
Kian-Meng Ang <kianmeng.ang@gmail.com>
Kjetil Jørgensen <kjetijor+github@gmail.com>
Klas Mellbourn <klas@mellbourn.net>
Koichi Murase <myoga.murase@gmail.com>
Korvin Szanto <Korvinszanto@gmail.com>
Krithic Kumar <30691152+notjedi@users.noreply.github.com>
Krut Patel <kroot.patel@gmail.com>
Laurent le Beau-Martin <1180863+laurentlbm@users.noreply.github.com>
lchausmann <jazz-github@zqz.dk>
LeoniePhiline <22329650+LeoniePhiline@users.noreply.github.com>
Luca Comellini <luca.com@gmail.com>
Lucas Burns <44355502+lmburns@users.noreply.github.com>
Lucas Trzesniewski <lucas.trzesniewski@gmail.com>
Lucy <lucy@absolucy.moe>
Luke Baker <lukebaker@gmail.com>
Luke Karrys <luke@lukekarrys.com>
Mag Mell <sakiiily@aosc.io>
Manel Vilar <manelvf@gmail.com>
Marcin Puc <tranzystorek.io@protonmail.com>
Marijan Smetko <msmetko@msmetko.xyz>
Mark Wotton <mwotton@gmail.com>
Martin Indra <martin.indra@mgn.cz>
Martin Junghanns <m.junghanns@mailbox.org>
Mat Jones <mat@mjones.network>
Matheus Martins <matheuscumth@gmail.com>
Matt Godbolt <matt@godbolt.org>
Matthew Berryman <matthew@acrossthecloud.net>
Matthias Beyer <mail@beyermatthias.de>
Matthieu LAURENT <matthieu.laurent69@protonmail.com>
Mattias Eriksson <mattias.eriksson@tutanota.com>
Maurice Escher <maurice.escher@sap.com>
Maxim Burgerhout <maxim@wzzrd.com>
Maxim Uvarov <maxim-uvarov@users.noreply.github.com>
mb6ockatf <104227451+mb6ockatf@users.noreply.github.com>
mentalisttraceur <mentalisttraceur@gmail.com>
Michael Bianco <iloveitaly@gmail.com>
Michael Mior <michael.mior@gmail.com>
Michael Vincent <377567+Vynce@users.noreply.github.com>
Michele Azzolari <michele@azzolari.it>
Michelle Tilley <michelle@michelletilley.net>
Mike Pastore <mwpastore@users.noreply.github.com>
Mike Tsao <mike@sowbug.com>
mmx <github@m2nx.com>
morguldir <morguldir@protonmail.com>
mundry <1453314+mundry@users.noreply.github.com>
Nelyah <Nelyah@users.noreply.github.com>
Nemo157 <git@nemo157.com>
networkException <git@nwex.de>
Nico Kokonas <nico@nicomee.com>
Niklas Hambüchen <mail@nh2.me>
noyez <noyez@ithryn.net>
Omer Katz <omer.drow@gmail.com>
onkelT2 <126604057+onkelT2@users.noreply.github.com>
Onè <43485962+c-git@users.noreply.github.com>
Orhun Parmaksız <orhunparmaksiz@gmail.com>
P T Weir <phil.weir@flaxandteal.co.uk>
Patrick <pmarschik@users.noreply.github.com>
Patrick Decat <pdecat@gmail.com>
Patrick Jackson <patrick@jackson.dev>
Pavel Ivanov <mr.pavel.ivanov@gmail.com>
Per Modin <pmodin@users.noreply.github.com>
Peter Brunner <peter@lugoues.net>
Peter Holloway <holloway.p.r@gmail.com>
Philippe Normand <phil@base-art.net>
Philippe Normand <philn@igalia.com>
Pierluigi <82404704+IoSonoPiero@users.noreply.github.com>
Plamen Dimitrov <pdimitrov@pevogam.com>
Poliorcetics <poliorcetics@users.noreply.github.com>
postmath <postmath@users.noreply.github.com>
printfn <1643883+printfn@users.noreply.github.com>
Qiming Xu <33349132+xqm32@users.noreply.github.com>
Rain <rain@sunshowers.io>
Ramses <ramses@well-founded.dev>
Remmy Cat Stock <3317423+remmycat@users.noreply.github.com>
Remo Senekowitsch <remo@buenzli.dev>
Reverier Xu <reverier.xu@outlook.com>
Richard de Boer <git@tubul.net>
Richard Jones <4550158+RichardDRJ@users.noreply.github.com>
Richard Turner <63139+zygous@users.noreply.github.com>
Robin Millette <robin@millette.info>
rriski <github@timoriski.fi>
Sam Edwards <sam@samedwards.ca>
Sam Lanning <sam@samlanning.com>
Samson <samson_gh@onepatchdown.net>
Sandro <sandro.jaeckel@gmail.com>
Satyarth Sampath <satyarth.23@gmail.com>
sdr135284 <54752759+sdr135284@users.noreply.github.com>
Shroomy <sporeventexplosion@gmail.com>
Simon <simon_bull@mckinsey.com>
Simon Elsbrock <simon@iodev.org>
slamp <slaamp@gmail.com>
Steve Kemp <steve@steve.org.uk>
Steven Xu <stevenxxiu@users.noreply.github.com>
Sven-Hendrik Haase <svenstaro@gmail.com>
Thomas Buckley-Houston <tom@tombh.co.uk>
Tobias Genannt <tobias.genannt@gmail.com>
Tobias Genannt <tobias.genannt@qbeyond.de>
Tobias Hunger <tobias.hunger@gmail.com>
Tom Cammann <cammann.tom@gmail.com>
Tom Cammann <tom.cammann@oracle.com>
Trygve Aaberge <trygveaa@gmail.com>
TymanWasTaken <tbeckman530@gmail.com>
Ubiquitous Photon <39134173+UbiquitousPhoton@users.noreply.github.com>
Violet Shreve <github@shreve.io>
Vlad Stepanov <8uk.8ak@gmail.com>
Vladislav Stepanov <8uk.8ak@gmail.com>
VuiMuich <jm.spam@gmx.net>
Webmaster At Cosmic DNA <92752640+DanielAtCosmicDNA@users.noreply.github.com>
Will Fancher <elvishjerricco@gmail.com>
Wind <WindSoilder@outlook.com>
WindSoilder <WindSoilder@outlook.com>
winston <hey@winston.sh>
wpbrz <61665187+wpbrz@users.noreply.github.com>
Xavier Vello <xavier.vello@gmail.com>
xfzv <78810647+xfzv@users.noreply.github.com>
Yannick Ulrich <yannick.ulrich@durham.ac.uk>
Yaroslav Halchenko <debian@onerussian.com>
Yolo <noah.chang@outlook.com>
Yonatan Goldschmidt <yon.goldschmidt@gmail.com>
YummyOreo <bobgim20@gmail.com>
Yuvi Panda <yuvipanda@gmail.com>
Zhanibek Adilbekov <zhanibek.adilbekov@proton.me>
ZhiHong Li <joker_lizhih@163.com>
Zhizhen He <hezhizhen.yi@gmail.com>
éclairevoyant <848000+eclairevoyant@users.noreply.github.com>
依云 <lilydjwg@gmail.com>
镜面王子 <153555712@qq.com>
================================================
FILE: Cargo.toml
================================================
[workspace]
members = ["crates/*", "crates/atuin-nucleo/matcher", "crates/atuin-nucleo/bench"]
resolver = "2"
exclude = ["ui/backend", "crates/atuin-nucleo/matcher/fuzz"]
[workspace.package]
version = "18.13.3"
authors = ["Ellie Huxtable <ellie@atuin.sh>"]
rust-version = "1.94.0"
license = "MIT"
homepage = "https://atuin.sh"
repository = "https://github.com/atuinsh/atuin"
readme = "README.md"
[workspace.dependencies]
async-trait = "0.1.58"
atuin-client = { path = "crates/atuin-client", version = "18.13.3" }
atuin-common = { path = "crates/atuin-common", version = "18.13.3" }
atuin-daemon = { path = "crates/atuin-daemon", version = "18.13.3" }
atuin-dotfiles = { path = "crates/atuin-dotfiles", version = "18.13.3" }
atuin-history = { path = "crates/atuin-history", version = "18.13.3" }
atuin-kv = { path = "crates/atuin-kv", version = "18.13.3" }
atuin-scripts = { path = "crates/atuin-scripts", version = "18.13.3" }
atuin-server = { path = "crates/atuin-server", version = "18.13.3" }
atuin-server-database = { path = "crates/atuin-server-database", version = "18.13.3" }
atuin-server-postgres = { path = "crates/atuin-server-postgres", version = "18.13.3" }
atuin-server-sqlite = { path = "crates/atuin-server-sqlite", version = "18.13.3" }
atuin-nucleo = { path = "crates/atuin-nucleo", version = "0.6.0" }
atuin-nucleo-matcher = { path = "crates/atuin-nucleo/matcher", version = "0.3.1" }
base64 = "0.22"
crossterm = "0.29.0"
log = "0.4"
time = { version = "0.3.47", features = [
"serde-human-readable",
"macros",
"local-offset",
] }
clap = { version = "4.5.7", features = ["derive"] }
config = { version = "0.15.8", default-features = false, features = ["toml"] }
directories = "6.0.0"
eyre = "0.6"
fs-err = "3.1"
interim = { version = "0.2.0", features = ["time_0_3"] }
itertools = "0.14.0"
rand = { version = "0.8.5", features = ["std"] }
semver = "1.0.20"
serde = { version = "1.0.202", features = ["derive"] }
serde_json = "1.0.119"
tokio = { version = "1", features = ["full"] }
uuid = { version = "1.9", features = ["v4", "v7", "serde"] }
whoami = "2.1.0"
typed-builder = "0.18.2"
pretty_assertions = "1.3.0"
thiserror = "2"
rustix = { version = "1.1.4", features = ["process", "fs"] }
tower = "0.5"
tracing = "0.1"
ratatui = "0.30.0"
sql-builder = "3"
tempfile = { version = "3.19" }
minijinja = "2.9.0"
rustls = { version = "0.23", default-features = false, features = [
"ring",
"std",
"tls12",
] }
[workspace.dependencies.tracing-subscriber]
version = "0.3"
features = ["ansi", "fmt", "registry", "env-filter", "json"]
[workspace.dependencies.reqwest]
version = "0.13"
features = ["json", "rustls-no-provider", "stream"]
default-features = false
[workspace.dependencies.sqlx]
version = "0.8"
features = ["runtime-tokio-rustls", "time", "postgres", "uuid"]
# The profile that 'cargo dist' will build with
[profile.dist]
inherits = "release"
lto = "thin"
strip = "symbols"
================================================
FILE: Dockerfile
================================================
FROM lukemathwalker/cargo-chef:latest-rust-1.94.0-slim-bookworm AS chef
WORKDIR app
FROM chef AS planner
COPY . .
RUN cargo chef prepare --recipe-path recipe.json
FROM chef AS builder
# Ensure working C compile setup (not installed by default in arm64 images)
RUN apt update && apt install build-essential -y
COPY --from=planner /app/recipe.json recipe.json
RUN cargo chef cook --release --recipe-path recipe.json
COPY . .
RUN cargo build --release --bin atuin-server
FROM debian:bookworm-20260202-slim AS runtime
RUN useradd -c 'atuin user' atuin && mkdir /config && chown atuin:atuin /config
# Install ca-certificates for webhooks to work
RUN apt update && apt install ca-certificates -y && rm -rf /var/lib/apt/lists/*
WORKDIR app
USER atuin
ENV TZ=Etc/UTC
ENV RUST_LOG=atuin_server=info
ENV ATUIN_CONFIG_DIR=/config
COPY --from=builder /app/target/release/atuin-server /usr/local/bin
ENTRYPOINT ["/usr/local/bin/atuin-server"]
================================================
FILE: LICENSE
================================================
MIT License
Copyright (c) 2021 Ellie Huxtable
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
================================================
FILE: README.md
================================================
<p align="center">
<picture>
<source media="(prefers-color-scheme: dark)" srcset="https://github.com/atuinsh/atuin/assets/53315310/13216a1d-1ac0-4c99-b0eb-d88290fe0efd">
<img alt="Text changing depending on mode. Light: 'So light!' Dark: 'So dark!'" src="https://github.com/atuinsh/atuin/assets/53315310/08bc86d4-a781-4aaa-8d7e-478ae6bcd129">
</picture>
</p>
<p align="center">
<em>magical shell history</em>
</p>
<hr/>
<p align="center">
<a href="https://github.com/atuinsh/atuin/actions?query=workflow%3ARust"><img src="https://img.shields.io/github/actions/workflow/status/atuinsh/atuin/rust.yml?style=flat-square" /></a>
<a href="https://crates.io/crates/atuin"><img src="https://img.shields.io/crates/v/atuin.svg?style=flat-square" /></a>
<a href="https://crates.io/crates/atuin"><img src="https://img.shields.io/crates/d/atuin.svg?style=flat-square" /></a>
<a href="https://github.com/atuinsh/atuin/blob/main/LICENSE"><img src="https://img.shields.io/crates/l/atuin.svg?style=flat-square" /></a>
<a href="https://discord.gg/Fq8bJSKPHh"><img src="https://img.shields.io/discord/954121165239115808" /></a>
<a rel="me" href="https://hachyderm.io/@atuin"><img src="https://img.shields.io/mastodon/follow/109944632283122560?domain=https%3A%2F%2Fhachyderm.io&style=social"/></a>
<a href="https://twitter.com/atuinsh"><img src="https://img.shields.io/twitter/follow/atuinsh?style=social" /></a>
</p>
[English] | [简体中文]
Atuin replaces your existing shell history with a SQLite database, and records
additional context for your commands. Additionally, it provides optional and
_fully encrypted_ synchronisation of your history between machines, via an Atuin
server.
<p align="center">
<img src="demo.gif" alt="animated" width="80%" />
</p>
<p align="center">
<em>exit code, duration, time and command shown</em>
</p>
As well as the search UI, it can do things like this:
```
# search for all successful `make` commands, recorded after 3pm yesterday
atuin search --exit 0 --after "yesterday 3pm" make
```
You may use either the server I host, or host your own! Or just don't use sync
at all. As all history sync is encrypted, I couldn't access your data even if
I wanted to. And I **really** don't want to.
## Features
- rebind `ctrl-r` and `up` (configurable) to a full screen history search UI
- store shell history in a sqlite database
- back up and sync **encrypted** shell history
- the same history across terminals, across sessions, and across machines
- log exit code, cwd, hostname, session, command duration, etc
- calculate statistics such as "most used command"
- old history file is not replaced
- quick-jump to previous items with <kbd>Alt-\<num\></kbd>
- switch filter modes via ctrl-r; search history just from the current session, directory, or globally
- enter to execute a command, tab to edit
## Documentation
- [Quickstart](#quickstart)
- [Install](https://docs.atuin.sh/guide/installation/)
- [Setting up sync](https://docs.atuin.sh/guide/sync/)
- [Import history](https://docs.atuin.sh/guide/import/)
- [Basic usage](https://docs.atuin.sh/guide/basic-usage/)
## Supported Shells
- zsh
- bash
- fish
- nushell
- xonsh
- powershell (tier 2 support)
## Community
### Forum
Atuin has a community forum, please ask here for help and support: <https://forum.atuin.sh/>
### IRC
We're also available via #atuin on libera.chat
### Discord
Atuin also has a community Discord, available [here](https://discord.gg/jR3tfchVvW)
# Quickstart
This will sign you up for the Atuin Cloud sync server. Everything is end-to-end encrypted, so your secrets are safe!
Read more in the [docs](https://docs.atuin.sh) for an offline setup, self hosted server, and more.
```
curl --proto '=https' --tlsv1.2 -LsSf https://setup.atuin.sh | sh
atuin register -u <USERNAME> -e <EMAIL>
atuin import auto
atuin sync
```
Then restart your shell!
> [!NOTE]
>
> **For Bash users**: The above sets up `bash-preexec` for necessary hooks, but
> `bash-preexec` has limitations. For details, please see the
> [Bash](https://docs.atuin.sh/guide/installation/#installing-the-shell-plugin)
> section of the shell plugin documentation.
# Security
If you find any security issues, we'd appreciate it if you could alert <ellie@atuin.sh>
# Contributors
<a href="https://github.com/atuinsh/atuin/graphs/contributors">
<img src="https://contrib.rocks/image?repo=atuinsh/atuin&max=300" />
</a>
Made with [contrib.rocks](https://contrib.rocks).
[English]: ./README.md
[简体中文]: ./docs-i18n/zh-CN/README.md
================================================
FILE: atuin.nix
================================================
# Atuin package definition
#
# This file will be similar to the package definition in nixpkgs:
# https://github.com/NixOS/nixpkgs/blob/master/pkgs/by-name/at/atuin/package.nix
#
# Helpful documentation: https://github.com/NixOS/nixpkgs/blob/master/doc/languages-frameworks/rust.section.md
{
lib,
stdenv,
installShellFiles,
rustPlatform,
libiconv,
}:
rustPlatform.buildRustPackage {
name = "atuin";
src = lib.cleanSource ./.;
cargoLock = {
lockFile = ./Cargo.lock;
# Allow dependencies to be fetched from git and avoid having to set the outputHashes manually
allowBuiltinFetchGit = true;
};
nativeBuildInputs = [installShellFiles];
buildInputs = lib.optionals stdenv.isDarwin [libiconv];
postInstall = ''
installShellCompletion --cmd atuin \
--bash <($out/bin/atuin gen-completions -s bash) \
--fish <($out/bin/atuin gen-completions -s fish) \
--zsh <($out/bin/atuin gen-completions -s zsh)
'';
doCheck = false;
meta = with lib; {
description = "Replacement for a shell history which records additional commands context with optional encrypted synchronization between machines";
homepage = "https://github.com/atuinsh/atuin";
license = licenses.mit;
mainProgram = "atuin";
};
}
================================================
FILE: atuin.plugin.zsh
================================================
# shellcheck disable=2148,SC2168,SC1090,SC2125
local FOUND_ATUIN=$+commands[atuin]
if [[ $FOUND_ATUIN -eq 1 ]]; then
source <(atuin init zsh)
fi
================================================
FILE: cliff.toml
================================================
# git-cliff ~ default configuration file
# https://git-cliff.org/docs/configuration
#
# Lines starting with "#" are comments.
# Configuration options are organized into tables and keys.
# See documentation for more information on available options.
[changelog]
# changelog header
header = """
# Changelog\n
All notable changes to this project will be documented in this file.\n
"""
# template for the changelog body
# https://keats.github.io/tera/docs/#introduction
body = """
{% if version %}\
## {{ version | trim_start_matches(pat="v") }}
{% else %}\
## [unreleased]
{% endif %}\
{% for group, commits in commits | group_by(attribute="group") %}
### {{ group | upper_first }}
{% for commit in commits
| filter(attribute="scope")
| sort(attribute="scope") %}
- *({{commit.scope}})* {{ commit.message | upper_first }}
{%- if commit.breaking %}
{% raw %} {% endraw %}- **BREAKING**: {{commit.breaking_description}}
{%- endif -%}
{%- endfor -%}
{% raw %}\n{% endraw %}\
{%- for commit in commits %}
{%- if commit.scope -%}
{% else -%}
- {{ commit.message | upper_first }}
{% if commit.breaking -%}
{% raw %} {% endraw %}- **BREAKING**: {{commit.breaking_description}}
{% endif -%}
{% endif -%}
{% endfor -%}
{% raw %}\n{% endraw %}\
{% endfor %}\n
"""
# remove the leading and trailing whitespace from the template
trim = true
# changelog footer
footer = """
<!-- generated by git-cliff -->
"""
# postprocessors
postprocessors = [
{ pattern = '<REPO>', replace = "https://github.com/atuinsh/atuin" }, # replace repository URL
]
[git]
# parse the commits based on https://www.conventionalcommits.org
conventional_commits = true
# filter out the commits that are not conventional
filter_unconventional = true
# process each line of a commit as an individual commit
split_commits = false
# regex for preprocessing the commit messages
commit_preprocessors = [
{ pattern = '\((\w+\s)?#([0-9]+)\)', replace = "([#${2}](<REPO>/issues/${2}))" }, # replace issue numbers
]
# regex for parsing and grouping commits
commit_parsers = [
{ message = "^feat", group = "Features" },
{ message = "^fix", group = "Bug Fixes" },
{ message = "^doc", group = "Documentation" },
{ message = "^perf", group = "Performance" },
{ message = "^refactor", group = "Refactor" },
{ message = "^style", group = "Styling" },
{ message = "^test", group = "Testing" },
{ message = "^chore\\(release\\): prepare for", skip = true },
{ message = "^chore\\(deps\\)", skip = true },
{ message = "^chore\\(pr\\)", skip = true },
{ message = "^chore\\(pull\\)", skip = true },
{ message = "^chore|ci", group = "Miscellaneous Tasks" },
{ body = ".*security", group = "Security" },
{ message = "^revert", group = "Revert" },
]
# protect breaking changes from being skipped due to matching a skipping commit_parser
protect_breaking_commits = false
# filter out the commits that are not matched by commit parsers
filter_commits = false
# regex for matching git tags
tag_pattern = "v[0-9].*"
# regex for skipping tags
skip_tags = "v0.1.0-beta.1"
# regex for ignoring tags
ignore_tags = "prerelease|beta|alpha"
# sort the tags topologically
topo_order = false
# sort the commits inside sections by oldest/newest order
sort_commits = "oldest"
# limit the number of commits included in the changelog.
# limit_commits = 42
================================================
FILE: crates/atuin/Cargo.toml
================================================
[package]
name = "atuin"
edition = "2024"
description = "atuin - magical shell history"
readme = "./README.md"
rust-version = { workspace = true }
version = { workspace = true }
authors = { workspace = true }
license = { workspace = true }
homepage = { workspace = true }
repository = { workspace = true }
[package.metadata.binstall]
pkg-url = "{ repo }/releases/download/v{ version }/{ name }-{ target }.tar.gz"
bin-dir = "{ name }-{ target }/{ bin }{ binary-ext }"
pkg-fmt = "tgz"
[package.metadata.deb]
maintainer = "Ellie Huxtable <ellie@elliehuxtable.com>"
copyright = "2021, Ellie Huxtable <ellie@elliehuxtable.com>"
license-file = ["LICENSE"]
depends = "$auto"
section = "utility"
[package.metadata.rpm]
package = "atuin"
[package.metadata.rpm.cargo]
buildflags = ["--release"]
[package.metadata.rpm.targets]
atuin = { path = "/usr/bin/atuin" }
[features]
default = ["client", "sync", "clipboard", "check-update", "daemon", "ai", "hex"]
client = ["atuin-client"]
sync = ["atuin-client/sync"]
daemon = ["atuin-client/daemon", "atuin-daemon"]
ai = ["atuin-ai"]
hex = ["atuin-hex"]
clipboard = ["arboard"]
check-update = ["atuin-client/check-update"]
[dependencies]
atuin-ai = { path = "../atuin-ai", version = "18.13.3", optional = true, default-features = false }
atuin-client = { path = "../atuin-client", version = "18.13.3", optional = true, default-features = false }
atuin-common = { workspace = true }
atuin-dotfiles = { workspace = true }
atuin-history = { workspace = true }
atuin-daemon = { path = "../atuin-daemon", version = "18.13.3", optional = true, default-features = false }
atuin-hex = { path = "../atuin-hex", version = "18.13.3", optional = true, default-features = false }
atuin-scripts = { workspace = true }
atuin-kv = { workspace = true }
log = { workspace = true }
time = { workspace = true }
eyre = { workspace = true }
indicatif = "0.18.0"
serde = { workspace = true }
serde_json = { workspace = true }
crossterm = { workspace = true, features = ["use-dev-tty"] }
unicode-width = "0.2"
itertools = { workspace = true }
tokio = { workspace = true }
async-trait = { workspace = true }
interim = { workspace = true }
clap = { workspace = true }
clap_complete = "4.5.8"
clap_complete_nushell = "4.5.4"
fs-err = { workspace = true }
fs4 = "0.13.1"
rpassword = "7.0"
semver = { workspace = true }
rustix = { workspace = true }
runtime-format = "0.1.3"
tiny-bip39 = "2"
futures-util = "0.3"
fuzzy-matcher = "0.3.7"
colored = "2.0.4"
open = "5"
ratatui = { workspace = true }
tracing = "0.1"
tracing-subscriber = { workspace = true }
tracing-appender = "0.2"
uuid = { workspace = true }
sysinfo = "0.30.7"
regex = "1.10.5"
norm = { version = "0.1.1", features = ["fzf-v2"] }
atuin-nucleo-matcher = { workspace = true }
tempfile = { workspace = true }
shlex = "1.3.0"
# settings editor with comment and relative ordering preservation
toml_edit = "0.25.4"
[target.'cfg(any(target_os = "windows", target_os = "macos"))'.dependencies]
arboard = { version = "3.4", optional = true }
[target.'cfg(target_os = "linux")'.dependencies]
arboard = { version = "3.4", optional = true, features = [
"wayland-data-control",
] }
[target.'cfg(unix)'.dependencies]
daemonize = "0.5.0"
[dev-dependencies]
tracing-tree = "0.4"
# Integration tests in tests/ spin up a test server to verify sync functionality.
# TODO: Consider moving these tests to atuin-server crate instead (client would become a dev dep there)
atuin-server = { workspace = true }
atuin-server-database = { workspace = true }
atuin-server-postgres = { workspace = true }
================================================
FILE: crates/atuin/LICENSE
================================================
MIT License
Copyright (c) 2021 Ellie Huxtable
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
================================================
FILE: crates/atuin/build.rs
================================================
use std::process::Command;
fn main() {
let output = Command::new("git").args(["rev-parse", "HEAD"]).output();
let sha = match output {
Ok(sha) => String::from_utf8(sha.stdout).unwrap(),
Err(_) => String::from("NO_GIT"),
};
println!("cargo:rustc-env=GIT_HASH={sha}");
}
================================================
FILE: crates/atuin/src/command/client/account/change_password.rs
================================================
use clap::Parser;
use eyre::{Result, bail};
use atuin_client::{
auth::{self, MutateResponse},
settings::Settings,
};
use rpassword::prompt_password;
#[derive(Parser, Debug)]
pub struct Cmd {
#[clap(long, short)]
pub current_password: Option<String>,
#[clap(long, short)]
pub new_password: Option<String>,
/// The two-factor authentication code for your account, if any
#[clap(long, short)]
pub totp_code: Option<String>,
}
impl Cmd {
pub async fn run(&self, settings: &Settings) -> Result<()> {
if !settings.logged_in().await? {
bail!("You are not logged in");
}
let client = auth::auth_client(settings).await;
let current_password = self.current_password.clone().unwrap_or_else(|| {
prompt_password("Please enter the current password: ")
.expect("Failed to read from input")
});
if current_password.is_empty() {
bail!("please provide the current password");
}
let new_password = self.new_password.clone().unwrap_or_else(|| {
prompt_password("Please enter the new password: ").expect("Failed to read from input")
});
if new_password.is_empty() {
bail!("please provide a new password");
}
let mut totp_code = self.totp_code.clone();
loop {
let response = client
.change_password(¤t_password, &new_password, totp_code.as_deref())
.await?;
match response {
MutateResponse::Success => break,
MutateResponse::TwoFactorRequired => {
totp_code = Some(super::login::or_user_input(None, "two-factor code"));
}
}
}
println!("Account password successfully changed!");
Ok(())
}
}
================================================
FILE: crates/atuin/src/command/client/account/delete.rs
================================================
use atuin_client::{
auth::{self, MutateResponse},
settings::Settings,
};
use clap::Parser;
use eyre::{Result, bail};
use super::login::{or_user_input, read_user_password};
#[derive(Parser, Debug)]
pub struct Cmd {
#[clap(long, short)]
pub password: Option<String>,
/// The two-factor authentication code for your account, if any
#[clap(long, short)]
pub totp_code: Option<String>,
}
impl Cmd {
pub async fn run(&self, settings: &Settings) -> Result<()> {
if !settings.logged_in().await? {
bail!("You are not logged in");
}
let client = auth::auth_client(settings).await;
let password = self.password.clone().unwrap_or_else(read_user_password);
if password.is_empty() {
bail!("please provide your password");
}
let mut totp_code = self.totp_code.clone();
loop {
let response = client
.delete_account(&password, totp_code.as_deref())
.await?;
match response {
MutateResponse::Success => break,
MutateResponse::TwoFactorRequired => {
totp_code = Some(or_user_input(None, "two-factor code"));
}
}
}
// Clean up sessions from meta store
let meta = Settings::meta_store().await?;
meta.delete_session().await?;
meta.delete_hub_session().await?;
println!("Your account is deleted");
Ok(())
}
}
================================================
FILE: crates/atuin/src/command/client/account/link.rs
================================================
use eyre::{Result, bail};
use atuin_client::settings::Settings;
pub async fn run(settings: &Settings) -> Result<()> {
let meta = Settings::meta_store().await?;
let cli_token = meta.session_token().await?;
let hub_token = meta.hub_session_token().await?;
let Some(cli_token) = cli_token else {
bail!("No CLI session found. Please log in first with 'atuin login'.");
};
let hub_address = settings.active_hub_endpoint().unwrap_or_default();
if hub_token.is_some() {
println!("Found both Hub and CLI sessions. Linking accounts...");
} else {
println!("Found CLI session but no Hub session. Logging in to Hub first...");
let session = atuin_client::hub::HubAuthSession::start(hub_address.as_ref()).await?;
println!("Open this URL to authenticate with Atuin Hub:");
println!("{}", session.auth_url);
let token = session
.wait_for_completion(
atuin_client::hub::DEFAULT_AUTH_TIMEOUT,
atuin_client::hub::DEFAULT_POLL_INTERVAL,
)
.await?;
atuin_client::hub::save_session(&token).await?;
println!("Hub authentication complete.");
}
atuin_client::hub::link_account(hub_address.as_ref(), &cli_token).await?;
println!("Successfully linked CLI account to Hub.");
Ok(())
}
================================================
FILE: crates/atuin/src/command/client/account/login.rs
================================================
use std::{io, path::PathBuf};
use clap::Parser;
use eyre::{Context, Result, bail};
use tokio::{fs::File, io::AsyncWriteExt};
use atuin_client::{
auth::{self, AuthResponse},
encryption::{Key, decode_key, encode_key, load_key},
record::sqlite_store::SqliteStore,
record::store::Store,
settings::Settings,
};
use rpassword::prompt_password;
#[derive(Parser, Debug)]
pub struct Cmd {
#[clap(long, short)]
pub username: Option<String>,
#[clap(long, short)]
pub password: Option<String>,
/// The encryption key for your account
#[clap(long, short)]
pub key: Option<String>,
/// The two-factor authentication code for your account, if any
#[clap(long, short)]
pub totp_code: Option<String>,
#[clap(long, hide = true)]
pub from_registration: bool,
}
fn get_input() -> Result<String> {
let mut input = String::new();
io::stdin().read_line(&mut input)?;
Ok(input.trim_end_matches(&['\r', '\n'][..]).to_string())
}
impl Cmd {
pub async fn run(&self, settings: &Settings, store: &SqliteStore) -> Result<()> {
if settings.logged_in().await? {
if settings.is_hub_sync() {
println!("You are authenticated with Atuin Hub.");
} else {
println!("You are already logged in.");
}
println!("Run 'atuin logout' to log out.");
return Ok(());
}
if settings.is_hub_sync() {
self.run_hub_login(settings, store).await
} else {
self.run_legacy_login(settings, store).await
}
}
/// Hub login: use the browser OAuth flow unless all three flags
/// (username, password, key) were provided for headless/CI use.
async fn run_hub_login(&self, settings: &Settings, store: &SqliteStore) -> Result<()> {
let endpoint = settings.active_hub_endpoint().unwrap_or_default();
if let Some(username) = &self.username {
// Headless login via v0 API (for CI / scripting).
let client = auth::auth_client(settings).await;
self.prompt_and_store_key(settings, store).await?;
let password = self.password.clone().unwrap_or_else(read_user_password);
let mut totp_code = self.totp_code.clone();
let session = loop {
let response = client
.login(username, &password, totp_code.as_deref())
.await?;
match response {
AuthResponse::Success { session } => break session,
AuthResponse::TwoFactorRequired => {
totp_code = Some(or_user_input(None, "two-factor code"));
}
}
};
Settings::meta_store()
.await?
.save_hub_session(&session)
.await?;
} else {
// Interactive login via browser OAuth flow.
if self.from_registration {
load_key(settings)?;
} else {
self.prompt_and_store_key(settings, store).await?;
}
self.ensure_hub_session(settings, endpoint.as_ref()).await?;
}
// Silently attempt to link CLI account to Hub if one exists
if let Ok(cli_token) = settings.session_token().await
&& let Err(e) = atuin_client::hub::link_account(endpoint.as_ref(), &cli_token).await
{
tracing::debug!("Could not link CLI account to Hub: {}", e);
}
println!("Successfully authenticated with Atuin Hub.");
Ok(())
}
/// Legacy login: always prompt for username/password interactively
/// (or accept them via flags).
async fn run_legacy_login(&self, settings: &Settings, store: &SqliteStore) -> Result<()> {
let username = or_user_input(self.username.clone(), "username");
let password = self.password.clone().unwrap_or_else(read_user_password);
self.prompt_and_store_key(settings, store).await?;
let client = auth::auth_client(settings).await;
let response = client.login(&username, &password, None).await?;
match response {
AuthResponse::Success { session } => {
Settings::meta_store().await?.save_session(&session).await?;
}
AuthResponse::TwoFactorRequired => {
// Legacy server doesn't support 2FA, so this shouldn't happen.
bail!("unexpected two-factor requirement from legacy server");
}
}
println!("Logged in!");
Ok(())
}
async fn ensure_hub_session(&self, _settings: &Settings, hub_address: &str) -> Result<()> {
tracing::info!("Authenticating with Atuin Hub...");
let session = atuin_client::hub::HubAuthSession::start(hub_address).await?;
println!("Open this URL to continue authenticating with Atuin Hub:");
println!("{}", session.auth_url);
let token = session
.wait_for_completion(
atuin_client::hub::DEFAULT_AUTH_TIMEOUT,
atuin_client::hub::DEFAULT_POLL_INTERVAL,
)
.await?;
tracing::info!("Authentication complete, saving session token");
atuin_client::hub::save_session(&token).await?;
Ok(())
}
async fn prompt_and_store_key(&self, settings: &Settings, store: &SqliteStore) -> Result<()> {
let key_path = settings.key_path.as_str();
let key_path = PathBuf::from(key_path);
println!("IMPORTANT");
println!(
"If you are already logged in on another machine, you must ensure that the key you use here is the same as the key you used there."
);
println!("You can find your key by running 'atuin key' on the other machine.");
println!("Do not share this key with anyone.");
println!("\nRead more here: https://docs.atuin.sh/guide/sync/#login \n");
let key = or_user_input(
self.key.clone(),
"encryption key [blank to use existing key file]",
);
// if provided, the key may be EITHER base64, or a bip mnemonic
// try to normalize on base64
let key = if key.is_empty() {
key
} else {
// try parse the key as a mnemonic...
match bip39::Mnemonic::from_phrase(&key, bip39::Language::English) {
Ok(mnemonic) => encode_key(Key::from_slice(mnemonic.entropy()))?,
Err(err) => {
match err {
// assume they copied in the base64 key
bip39::ErrorKind::InvalidWord(_) => key,
bip39::ErrorKind::InvalidChecksum => {
bail!("Key mnemonic is not valid")
}
bip39::ErrorKind::InvalidKeysize(_)
| bip39::ErrorKind::InvalidWordLength(_)
| bip39::ErrorKind::InvalidEntropyLength(_, _) => {
bail!("Key is not the correct length")
}
}
}
}
};
if key.is_empty() {
if key_path.exists() {
let bytes = fs_err::read_to_string(&key_path).context(format!(
"Existing key file at '{}' could not be read",
key_path.to_string_lossy()
))?;
if decode_key(bytes).is_err() {
bail!(format!(
"The key in existing key file at '{}' is invalid",
key_path.to_string_lossy()
));
}
} else {
panic!(
"No key provided and no existing key file found. Please use 'atuin key' on your other machine, or recover your key from a backup"
)
}
} else if !key_path.exists() {
if decode_key(key.clone()).is_err() {
bail!("The specified key is invalid");
}
let mut file = File::create(&key_path).await?;
file.write_all(key.as_bytes()).await?;
} else {
// we now know that the user has logged in specifying a key, AND that the key path
// exists
// 1. check if the saved key and the provided key match. if so, nothing to do.
// 2. if not, re-encrypt the local history and overwrite the key
let current_key: [u8; 32] = load_key(settings)?.into();
let encoded = key.clone(); // gonna want to save it in a bit
let new_key: [u8; 32] = decode_key(key)
.context("Could not decode provided key; is not valid base64-encoded key")?
.into();
if new_key != current_key {
println!("\nRe-encrypting local store with new key");
store.re_encrypt(¤t_key, &new_key).await?;
println!("Writing new key");
let mut file = File::create(&key_path).await?;
file.write_all(encoded.as_bytes()).await?;
}
}
Ok(())
}
}
pub(super) fn or_user_input(value: Option<String>, name: &'static str) -> String {
value.unwrap_or_else(|| read_user_input(name))
}
pub(super) fn read_user_password() -> String {
let password = prompt_password("Please enter password: ");
password.expect("Failed to read from input")
}
fn read_user_input(name: &'static str) -> String {
eprint!("Please enter {name}: ");
get_input().expect("Failed to read from input")
}
#[cfg(test)]
mod tests {
use atuin_client::encryption::Key;
#[test]
fn mnemonic_round_trip() {
let key = Key::from([
3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5, 8, 9, 7, 9, 3, 2, 3, 8, 4, 6, 2, 6, 4, 3, 3, 8, 3, 2,
7, 9, 5,
]);
let phrase = bip39::Mnemonic::from_entropy(&key, bip39::Language::English)
.unwrap()
.into_phrase();
let mnemonic = bip39::Mnemonic::from_phrase(&phrase, bip39::Language::English).unwrap();
assert_eq!(mnemonic.entropy(), key.as_slice());
assert_eq!(
phrase,
"adapt amused able anxiety mother adapt beef gaze amount else seat alcohol cage lottery avoid scare alcohol cactus school avoid coral adjust catch pink"
);
}
}
================================================
FILE: crates/atuin/src/command/client/account/logout.rs
================================================
use eyre::Result;
pub async fn run() -> Result<()> {
atuin_client::logout::logout().await
}
================================================
FILE: crates/atuin/src/command/client/account/register.rs
================================================
use clap::Parser;
use eyre::{Result, bail};
use super::login::or_user_input;
use atuin_client::{
auth::{self, AuthResponse},
record::sqlite_store::SqliteStore,
settings::Settings,
};
#[derive(Parser, Debug)]
pub struct Cmd {
#[clap(long, short)]
pub username: Option<String>,
#[clap(long, short)]
pub password: Option<String>,
#[clap(long, short)]
pub email: Option<String>,
}
impl Cmd {
pub async fn run(&self, settings: &Settings, store: &SqliteStore) -> Result<()> {
if settings.logged_in().await? {
if settings.is_hub_sync() {
println!("You are already authenticated with Atuin Hub.");
} else {
println!("You are already logged in.");
}
println!("Run 'atuin logout' to log out.");
return Ok(());
}
if settings.is_hub_sync() {
let required_for_headless = 3;
let provided = [
self.username.is_some(),
self.email.is_some(),
self.password.is_some(),
]
.iter()
.filter(|&b| *b)
.count();
if provided < required_for_headless {
println!(
"Username, password, and email are all required for headless registration. Continuing with interactive registration.\n"
);
}
if let (Some(username), Some(email), Some(password)) =
(&self.username, &self.email, &self.password)
{
// Headless registration via v0 API (for CI / scripting).
let client = auth::auth_client(settings).await;
if password.is_empty() {
bail!("please provide a password");
}
let response = client.register(username, email, password).await?;
match response {
AuthResponse::Success { session } => {
Settings::meta_store()
.await?
.save_hub_session(&session)
.await?;
}
AuthResponse::TwoFactorRequired => {
bail!("unexpected two-factor requirement during registration");
}
}
let _key = atuin_client::encryption::load_key(settings)?;
println!(
"Registration successful! Please make a note of your key (run 'atuin key') and keep it safe."
);
println!(
"You will need it to log in on other devices, and we cannot help recover it if you lose it."
);
} else {
// Interactive registration: delegate to the browser OAuth flow.
// Registration on Hub happens on the website; the CLI just needs
// to authenticate afterwards.
super::login::Cmd {
username: None,
password: None,
key: None,
totp_code: None,
from_registration: true,
}
.run(settings, store)
.await?;
}
} else {
// Legacy registration flow
println!("Registering for an Atuin Sync account");
let username = or_user_input(self.username.clone(), "username");
let email = or_user_input(self.email.clone(), "email");
let password = self
.password
.clone()
.unwrap_or_else(super::login::read_user_password);
if password.is_empty() {
bail!("please provide a password");
}
let session = atuin_client::api_client::register(
settings.sync_address.as_str(),
&username,
&email,
&password,
)
.await?;
let meta = Settings::meta_store().await?;
meta.save_session(&session.session).await?;
let _key = atuin_client::encryption::load_key(settings)?;
println!(
"Registration successful! Please make a note of your key (run 'atuin key') and keep it safe."
);
println!(
"You will need it to log in on other devices, and we cannot help recover it if you lose it."
);
}
Ok(())
}
}
================================================
FILE: crates/atuin/src/command/client/account.rs
================================================
use clap::{Args, Subcommand};
use eyre::Result;
use atuin_client::record::sqlite_store::SqliteStore;
use atuin_client::settings::Settings;
pub mod change_password;
pub mod delete;
pub mod link;
pub mod login;
pub mod logout;
pub mod register;
#[derive(Args, Debug)]
pub struct Cmd {
#[command(subcommand)]
command: Commands,
}
#[derive(Subcommand, Debug)]
pub enum Commands {
/// Login to the configured server
Login(login::Cmd),
/// Register a new account
Register(register::Cmd),
/// Log out
Logout,
/// Delete your account, and all synced data
Delete(delete::Cmd),
/// Change your password
ChangePassword(change_password::Cmd),
/// Link your CLI sync account to your Hub account
Link,
}
impl Cmd {
pub async fn run(self, settings: Settings, store: SqliteStore) -> Result<()> {
match self.command {
Commands::Login(l) => l.run(&settings, &store).await,
Commands::Register(r) => r.run(&settings, &store).await,
Commands::Logout => logout::run().await,
Commands::Delete(d) => d.run(&settings).await,
Commands::ChangePassword(c) => c.run(&settings).await,
Commands::Link => link::run(&settings).await,
}
}
}
================================================
FILE: crates/atuin/src/command/client/daemon.rs
================================================
use std::fs::{self, File, OpenOptions};
use std::io::{ErrorKind, Write};
#[cfg(unix)]
use std::os::unix::net::UnixStream as StdUnixStream;
use std::path::{Path, PathBuf};
use std::process::{Command, Stdio};
use std::time::{Duration, Instant};
use atuin_client::{
database::Sqlite, history::History, record::sqlite_store::SqliteStore, settings::Settings,
};
use atuin_daemon::client::{DaemonClientErrorKind, HistoryClient, classify_error};
use clap::Subcommand;
#[cfg(unix)]
use daemonize::Daemonize;
use eyre::{Result, WrapErr, bail, eyre};
use fs4::fs_std::FileExt;
use tokio::time::sleep;
#[derive(clap::Args, Debug)]
pub struct Cmd {
/// Internal flag for daemonization
#[arg(long, hide = true)]
daemonize: bool,
/// Also write daemon logs to the console (useful for debugging)
#[arg(long)]
show_logs: bool,
#[command(subcommand)]
subcmd: Option<SubCmd>,
}
#[derive(Subcommand, Debug)]
#[command(infer_subcommands = true)]
pub enum SubCmd {
/// Start the daemon server
Start {
#[arg(long, hide = true)]
daemonize: bool,
/// Also write daemon logs to the console (useful for debugging)
#[arg(long)]
show_logs: bool,
/// Force start: kill existing daemon process and reset the socket
#[arg(long)]
force: bool,
},
/// Show the daemon's current status
Status,
/// Stop the daemon gracefully
Stop,
/// Restart the daemon (stop, then start in background)
Restart,
}
impl Cmd {
/// Returns `true` when the process should daemonize before creating the
/// async runtime or opening any database connections.
#[cfg(unix)]
pub fn should_daemonize(&self) -> bool {
match &self.subcmd {
Some(SubCmd::Start { daemonize, .. }) => *daemonize,
None => self.daemonize,
_ => false,
}
}
/// Returns `true` when logs should also be written to the console.
pub fn show_logs(&self) -> bool {
match &self.subcmd {
Some(SubCmd::Start { show_logs, .. }) => *show_logs,
None => self.show_logs,
_ => false,
}
}
pub async fn run(
self,
settings: Settings,
store: SqliteStore,
history_db: Sqlite,
) -> Result<()> {
match self.subcmd {
None => {
eprintln!("Warning: `atuin daemon` is deprecated, use `atuin daemon start`");
run(settings, store, history_db, false).await
}
Some(SubCmd::Start { force, .. }) => run(settings, store, history_db, force).await,
Some(SubCmd::Status) => status_cmd(&settings).await,
Some(SubCmd::Stop) => stop_cmd(&settings).await,
Some(SubCmd::Restart) => restart_cmd(&settings).await,
}
}
}
const DAEMON_VERSION: &str = env!("CARGO_PKG_VERSION");
const DAEMON_PROTOCOL_VERSION: u32 = 1;
const STARTUP_POLL: Duration = Duration::from_millis(40);
const LOCK_POLL: Duration = Duration::from_millis(20);
const LEGACY_DAEMON_RESTART_MESSAGE: &str = "legacy daemon detected; restart daemon manually";
struct PidfileGuard {
file: File,
}
impl PidfileGuard {
fn acquire(path: &Path) -> Result<Self> {
let mut file = open_lock_file(path)?;
if !file.try_lock_exclusive()? {
bail!(
"daemon already running (pidfile lock busy at {})",
path.display()
);
}
file.set_len(0)
.wrap_err_with(|| format!("could not truncate daemon pidfile {}", path.display()))?;
writeln!(file, "{}", std::process::id())
.and_then(|()| writeln!(file, "{DAEMON_VERSION}"))
.wrap_err_with(|| format!("could not write daemon pidfile {}", path.display()))?;
Ok(Self { file })
}
}
impl Drop for PidfileGuard {
fn drop(&mut self) {
let _ = self.file.unlock();
}
}
enum Probe {
Ready(HistoryClient),
NeedsRestart(String),
Unreachable(eyre::Report),
}
fn daemon_matches_expected(version: &str, protocol: u32) -> bool {
version == DAEMON_VERSION && protocol == DAEMON_PROTOCOL_VERSION
}
fn daemon_mismatch_message(version: &str, protocol: u32) -> String {
if protocol == DAEMON_PROTOCOL_VERSION {
format!("daemon is out of date: expected {DAEMON_VERSION}, got {version}")
} else {
format!("daemon protocol mismatch: expected {DAEMON_PROTOCOL_VERSION}, got {protocol}")
}
}
fn is_legacy_daemon_error(err: &eyre::Report) -> bool {
matches!(classify_error(err), DaemonClientErrorKind::Unimplemented)
}
fn should_retry_after_error(err: &eyre::Report) -> bool {
matches!(
classify_error(err),
DaemonClientErrorKind::Connect
| DaemonClientErrorKind::Unavailable
| DaemonClientErrorKind::Unimplemented
)
}
fn daemon_startup_lock_path(pidfile_path: &Path) -> PathBuf {
let mut os = pidfile_path.as_os_str().to_os_string();
os.push(".startup.lock");
PathBuf::from(os)
}
fn open_lock_file(path: &Path) -> Result<File> {
if let Some(parent) = path.parent() {
fs::create_dir_all(parent)
.wrap_err_with(|| format!("could not create lock directory {}", parent.display()))?;
}
OpenOptions::new()
.read(true)
.write(true)
.create(true)
.truncate(false)
.open(path)
.wrap_err_with(|| format!("could not open lock file {}", path.display()))
}
async fn wait_for_lock(path: &Path, timeout: Duration) -> Result<File> {
let file = open_lock_file(path)?;
let start = Instant::now();
loop {
match file.try_lock_exclusive() {
Ok(true) => return Ok(file),
Ok(false) => {
if start.elapsed() >= timeout {
bail!("timed out waiting for lock at {}", path.display());
}
sleep(LOCK_POLL).await;
}
Err(err) => {
return Err(eyre!("could not lock {}: {err}", path.display()));
}
}
}
}
async fn wait_for_pidfile_available(path: &Path, timeout: Duration) -> Result<()> {
let file = wait_for_lock(path, timeout).await?;
file.unlock()
.wrap_err_with(|| format!("failed to unlock {}", path.display()))?;
Ok(())
}
async fn connect_client(settings: &Settings) -> Result<HistoryClient> {
HistoryClient::new(
#[cfg(not(unix))]
settings.daemon.tcp_port,
#[cfg(unix)]
settings.daemon.socket_path.clone(),
)
.await
}
async fn probe(settings: &Settings) -> Probe {
let mut client = match connect_client(settings).await {
Ok(client) => client,
Err(err) => return Probe::Unreachable(err),
};
match client.status().await {
Ok(status) => {
if daemon_matches_expected(&status.version, status.protocol) {
Probe::Ready(client)
} else {
Probe::NeedsRestart(daemon_mismatch_message(&status.version, status.protocol))
}
}
Err(err) => Probe::Unreachable(err),
}
}
async fn request_shutdown(settings: &Settings) {
if let Ok(mut client) = connect_client(settings).await {
let _ = client.shutdown().await;
}
}
fn spawn_daemon_process() -> Result<()> {
let exe = std::env::current_exe().wrap_err("could not locate atuin executable")?;
let mut cmd = Command::new(exe);
cmd.arg("daemon")
.arg("start")
.stdin(Stdio::null())
.stdout(Stdio::null())
.stderr(Stdio::null());
#[cfg(unix)]
cmd.arg("--daemonize");
cmd.spawn().wrap_err("failed to spawn daemon process")?;
Ok(())
}
fn startup_timeout(settings: &Settings) -> Duration {
Duration::from_secs_f64(settings.local_timeout.max(0.5) + 2.0)
}
#[cfg(unix)]
fn remove_stale_socket_if_present(settings: &Settings) -> Result<()> {
if settings.daemon.systemd_socket {
return Ok(());
}
let socket_path = Path::new(&settings.daemon.socket_path);
if !socket_path.exists() {
return Ok(());
}
match StdUnixStream::connect(socket_path) {
Ok(stream) => {
drop(stream);
Ok(())
}
Err(err) if err.kind() == ErrorKind::ConnectionRefused => {
fs::remove_file(socket_path).wrap_err_with(|| {
format!(
"failed to remove stale daemon socket {}",
socket_path.display()
)
})?;
Ok(())
}
Err(err) if err.kind() == ErrorKind::NotFound => Ok(()),
Err(_) => Ok(()),
}
}
async fn wait_until_ready(settings: &Settings, timeout: Duration) -> Result<HistoryClient> {
let start = Instant::now();
let mut last_error = eyre!("daemon did not become ready");
loop {
match probe(settings).await {
Probe::Ready(client) => return Ok(client),
Probe::NeedsRestart(reason) => {
last_error = eyre!(reason);
}
Probe::Unreachable(err) => {
if is_legacy_daemon_error(&err) {
return Err(err.wrap_err(LEGACY_DAEMON_RESTART_MESSAGE));
}
last_error = err;
}
}
if start.elapsed() >= timeout {
return Err(last_error.wrap_err(format!(
"timed out waiting for daemon startup after {}ms",
timeout.as_millis()
)));
}
sleep(STARTUP_POLL).await;
}
}
fn ensure_autostart_supported(settings: &Settings) -> Result<()> {
#[cfg(unix)]
if settings.daemon.systemd_socket {
bail!(
"daemon autostart is incompatible with `daemon.systemd_socket = true`; use systemd to manage the daemon"
);
}
#[cfg(not(unix))]
let _ = settings;
Ok(())
}
async fn restart_daemon(settings: &Settings) -> Result<HistoryClient> {
ensure_autostart_supported(settings)?;
let timeout = startup_timeout(settings);
let pidfile_path = PathBuf::from(&settings.daemon.pidfile_path);
let startup_lock_path = daemon_startup_lock_path(&pidfile_path);
let startup_lock = wait_for_lock(&startup_lock_path, timeout).await?;
match probe(settings).await {
Probe::Ready(client) => {
drop(startup_lock);
return Ok(client);
}
Probe::NeedsRestart(_) => {
request_shutdown(settings).await;
}
Probe::Unreachable(err) => {
if is_legacy_daemon_error(&err) {
return Err(err.wrap_err(LEGACY_DAEMON_RESTART_MESSAGE));
}
}
}
// This prevents rapid-fire hook invocations from racing daemon restart.
wait_for_pidfile_available(&pidfile_path, timeout).await?;
#[cfg(unix)]
remove_stale_socket_if_present(settings)?;
spawn_daemon_process()?;
let client = wait_until_ready(settings, timeout).await?;
drop(startup_lock);
Ok(client)
}
fn ensure_reply_compatible(settings: &Settings, version: &str, protocol: u32) -> Result<()> {
if daemon_matches_expected(version, protocol) {
return Ok(());
}
let message = daemon_mismatch_message(version, protocol);
if settings.daemon.autostart {
bail!("{message}");
}
bail!("{message}. Enable `daemon.autostart = true` or restart the daemon manually");
}
pub async fn start_history(settings: &Settings, history: History) -> Result<String> {
match async {
connect_client(settings)
.await?
.start_history(history.clone())
.await
}
.await
{
Ok(resp) => {
if daemon_matches_expected(&resp.version, resp.protocol) {
return Ok(resp.id);
}
if !settings.daemon.autostart {
return Err(eyre!(
"{}. Enable `daemon.autostart = true` or restart the daemon manually",
daemon_mismatch_message(&resp.version, resp.protocol)
));
}
}
Err(err) if !settings.daemon.autostart => return Err(err),
Err(err) if !should_retry_after_error(&err) => return Err(err),
Err(_) => {}
}
let resp = restart_daemon(settings)
.await?
.start_history(history)
.await?;
ensure_reply_compatible(settings, &resp.version, resp.protocol)?;
Ok(resp.id)
}
pub async fn end_history(settings: &Settings, id: String, duration: u64, exit: i64) -> Result<()> {
match async {
connect_client(settings)
.await?
.end_history(id.clone(), duration, exit)
.await
}
.await
{
Ok(resp) => {
if daemon_matches_expected(&resp.version, resp.protocol) {
return Ok(());
}
if !settings.daemon.autostart {
return Err(eyre!(
"{}. Enable `daemon.autostart = true` or restart the daemon manually",
daemon_mismatch_message(&resp.version, resp.protocol)
));
}
// End succeeded on the running daemon, so avoid replaying it.
// We only restart to make subsequent hook calls target the expected version.
let _ = restart_daemon(settings).await;
return Ok(());
}
Err(err) if !settings.daemon.autostart => return Err(err),
Err(err) if !should_retry_after_error(&err) => return Err(err),
Err(_) => {}
}
let resp = restart_daemon(settings)
.await?
.end_history(id, duration, exit)
.await?;
ensure_reply_compatible(settings, &resp.version, resp.protocol)?;
Ok(())
}
async fn status_cmd(settings: &Settings) -> Result<()> {
match probe(settings).await {
Probe::Ready(mut client) => {
let status = client.status().await?;
println!("Daemon running");
println!(" PID: {}", status.pid);
println!(" Version: {}", status.version);
println!(" Protocol: {}", status.protocol);
println!(" Healthy: {}", status.healthy);
#[cfg(unix)]
println!(" Socket: {}", settings.daemon.socket_path);
#[cfg(not(unix))]
println!(" Port: {}", settings.daemon.tcp_port);
}
Probe::NeedsRestart(reason) => {
println!("Daemon running (needs restart)");
println!(" Reason: {reason}");
}
Probe::Unreachable(_) => {
println!("Daemon is not running");
}
}
Ok(())
}
async fn stop_cmd(settings: &Settings) -> Result<()> {
let Ok(mut client) = connect_client(settings).await else {
println!("Daemon is not running");
return Ok(());
};
match client.shutdown().await {
Ok(true) => {
println!("Shutdown requested");
let pidfile_path = PathBuf::from(&settings.daemon.pidfile_path);
let timeout = Duration::from_secs(5);
match wait_for_pidfile_available(&pidfile_path, timeout).await {
Ok(()) => println!("Daemon stopped"),
Err(_) => println!("Daemon may still be shutting down"),
}
Ok(())
}
Ok(false) => bail!("Daemon rejected shutdown request"),
Err(err) => Err(err.wrap_err("Failed to send shutdown request")),
}
}
async fn restart_cmd(settings: &Settings) -> Result<()> {
// Stop if running
match probe(settings).await {
Probe::Ready(_) | Probe::NeedsRestart(_) => {
request_shutdown(settings).await;
println!("Stopping daemon...");
let pidfile_path = PathBuf::from(&settings.daemon.pidfile_path);
let timeout = Duration::from_secs(5);
wait_for_pidfile_available(&pidfile_path, timeout)
.await
.wrap_err("Timed out waiting for old daemon to stop")?;
}
Probe::Unreachable(_) => {
println!("No daemon running");
}
}
#[cfg(unix)]
remove_stale_socket_if_present(settings)?;
spawn_daemon_process()?;
println!("Starting daemon...");
let timeout = startup_timeout(settings);
let status = wait_until_ready(settings, timeout).await?.status().await?;
println!("Daemon restarted");
println!(" PID: {}", status.pid);
println!(" Version: {}", status.version);
Ok(())
}
/// Daemonize the current process. Must be called before creating the tokio
/// runtime or opening database connections, since `fork()` inside an async
/// runtime corrupts its internal state.
#[cfg(unix)]
pub fn daemonize_current_process() -> Result<()> {
let cwd =
std::env::current_dir().wrap_err("could not determine current directory for daemon")?;
Daemonize::new()
.working_directory(cwd)
.start()
.wrap_err("failed to daemonize process")?;
Ok(())
}
async fn run(
settings: Settings,
store: SqliteStore,
history_db: Sqlite,
force: bool,
) -> Result<()> {
if force {
force_cleanup(&settings);
}
let pidfile_path = PathBuf::from(&settings.daemon.pidfile_path);
let _pidfile_guard = PidfileGuard::acquire(&pidfile_path)?;
atuin_daemon::boot(settings, store, history_db).await?;
Ok(())
}
/// Force cleanup: kill existing daemon process and remove socket.
fn force_cleanup(settings: &Settings) {
let pidfile_path = Path::new(&settings.daemon.pidfile_path);
// Read and kill the existing process if pidfile exists
if pidfile_path.exists() {
if let Ok(contents) = fs::read_to_string(pidfile_path)
&& let Some(pid_str) = contents.lines().next()
&& let Ok(pid) = pid_str.parse::<u32>()
{
kill_process(pid);
// Give it a moment to release resources
std::thread::sleep(Duration::from_millis(100));
}
// Remove the pidfile
if let Err(e) = fs::remove_file(pidfile_path)
&& e.kind() != ErrorKind::NotFound
{
tracing::warn!("failed to remove pidfile: {e}");
}
}
// Remove the socket file
#[cfg(unix)]
{
let socket_path = Path::new(&settings.daemon.socket_path);
if socket_path.exists()
&& let Err(e) = fs::remove_file(socket_path)
&& e.kind() != ErrorKind::NotFound
{
tracing::warn!("failed to remove socket: {e}");
}
}
}
/// Kill a process by PID.
#[cfg(unix)]
fn kill_process(pid: u32) {
// Use kill command to send SIGTERM for graceful shutdown
let _ = Command::new("kill")
.args(["-TERM", &pid.to_string()])
.stdout(Stdio::null())
.stderr(Stdio::null())
.status();
}
/// Kill a process by PID.
#[cfg(not(unix))]
fn kill_process(pid: u32) {
// On Windows, use taskkill
let _ = Command::new("taskkill")
.args(["/PID", &pid.to_string(), "/F"])
.stdout(Stdio::null())
.stderr(Stdio::null())
.status();
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_version_matches() {
assert!(daemon_matches_expected(
DAEMON_VERSION,
DAEMON_PROTOCOL_VERSION
));
}
#[test]
fn test_version_mismatch() {
assert!(!daemon_matches_expected("0.0.0", DAEMON_PROTOCOL_VERSION));
assert!(!daemon_matches_expected(DAEMON_VERSION, 999));
assert!(!daemon_matches_expected("0.0.0", 999));
}
#[test]
fn test_mismatch_message_version() {
let msg = daemon_mismatch_message("0.0.0", DAEMON_PROTOCOL_VERSION);
assert!(msg.contains("out of date"), "got: {msg}");
assert!(msg.contains("0.0.0"));
assert!(msg.contains(DAEMON_VERSION));
}
#[test]
fn test_mismatch_message_protocol() {
let msg = daemon_mismatch_message(DAEMON_VERSION, 999);
assert!(msg.contains("protocol mismatch"), "got: {msg}");
}
#[test]
fn test_startup_lock_path() {
let pidfile = Path::new("/tmp/atuin-daemon.pid");
let lock = daemon_startup_lock_path(pidfile);
assert_eq!(lock, PathBuf::from("/tmp/atuin-daemon.pid.startup.lock"));
}
#[test]
fn test_pidfile_guard_acquire_and_drop() {
let tmp = tempfile::tempdir().unwrap();
let pidfile = tmp.path().join("daemon.pid");
{
let _guard = PidfileGuard::acquire(&pidfile).unwrap();
// Guard holds an exclusive lock — on Windows other handles cannot
// read the file, so we verify contents after the guard is dropped.
}
let contents = std::fs::read_to_string(&pidfile).unwrap();
let lines: Vec<&str> = contents.lines().collect();
assert_eq!(lines.len(), 2);
assert_eq!(lines[0], std::process::id().to_string());
assert_eq!(lines[1], DAEMON_VERSION);
// After guard is dropped, lock should be released — acquiring again must succeed.
let _guard2 = PidfileGuard::acquire(&pidfile).unwrap();
}
#[test]
fn test_pidfile_guard_prevents_double_acquire() {
let tmp = tempfile::tempdir().unwrap();
let pidfile = tmp.path().join("daemon.pid");
let _guard = PidfileGuard::acquire(&pidfile).unwrap();
let result = PidfileGuard::acquire(&pidfile);
assert!(result.is_err());
}
}
================================================
FILE: crates/atuin/src/command/client/default_config.rs
================================================
use atuin_client::settings::Settings;
pub fn run() {
println!("{}", Settings::example_config());
}
================================================
FILE: crates/atuin/src/command/client/doctor.rs
================================================
use std::process::Command;
use std::{env, str::FromStr};
use atuin_client::database::Sqlite;
use atuin_client::settings::Settings;
use atuin_common::shell::{Shell, shell_name};
use atuin_common::utils;
use colored::Colorize;
use eyre::Result;
use serde::Serialize;
use sysinfo::{Disks, System, get_current_pid};
#[derive(Debug, Serialize)]
struct ShellInfo {
pub name: String,
// best-effort, not supported on all OSes
pub default: String,
// Detect some shell plugins that the user has installed.
// I'm just going to start with preexec/blesh
pub plugins: Vec<String>,
// The preexec framework used in the current session, if Atuin is loaded.
pub preexec: Option<String>,
}
impl ShellInfo {
// HACK ALERT!
// Many of the shell vars we need to detect are not exported :(
// So, we're going to run a interactive session and directly check the
// variable. There's a chance this won't work, so it should not be fatal.
//
// Every shell we support handles `shell -ic 'command'`
fn shellvar_exists(shell: &str, var: &str) -> bool {
let cmd = Command::new(shell)
.args([
"-ic",
format!("[ -z ${var} ] || echo ATUIN_DOCTOR_ENV_FOUND").as_str(),
])
.output()
.map_or(String::new(), |v| {
let out = v.stdout;
String::from_utf8(out).unwrap_or_default()
});
cmd.contains("ATUIN_DOCTOR_ENV_FOUND")
}
fn detect_preexec_framework(shell: &str) -> Option<String> {
if env::var("ATUIN_SESSION").ok().is_none() {
None
} else if shell.starts_with("bash") || shell == "sh" {
env::var("ATUIN_PREEXEC_BACKEND")
.ok()
.filter(|value| !value.is_empty())
.and_then(|atuin_preexec_backend| {
atuin_preexec_backend.rfind(':').and_then(|pos_colon| {
u32::from_str(&atuin_preexec_backend[..pos_colon])
.ok()
.is_some_and(|preexec_shlvl| {
env::var("SHLVL")
.ok()
.and_then(|shlvl| u32::from_str(&shlvl).ok())
.is_some_and(|shlvl| shlvl == preexec_shlvl)
})
.then(|| atuin_preexec_backend[pos_colon + 1..].to_string())
})
})
} else {
Some("built-in".to_string())
}
}
fn validate_plugin_blesh(
_shell: &str,
shell_process: &sysinfo::Process,
ble_session_id: &str,
) -> Option<String> {
ble_session_id
.split('/')
.nth(1)
.and_then(|field| u32::from_str(field).ok())
.filter(|&blesh_pid| blesh_pid == shell_process.pid().as_u32())
.map(|_| "blesh".to_string())
}
pub fn plugins(shell: &str, shell_process: &sysinfo::Process) -> Vec<String> {
// consider a different detection approach if there are plugins
// that don't set shell vars
enum PluginShellType {
Any,
Bash,
// Note: these are currently unused
#[allow(dead_code)]
Zsh,
#[allow(dead_code)]
Fish,
#[allow(dead_code)]
Nushell,
#[allow(dead_code)]
Xonsh,
}
enum PluginProbeType {
EnvironmentVariable(&'static str),
InteractiveShellVariable(&'static str),
}
type PluginValidator = fn(&str, &sysinfo::Process, &str) -> Option<String>;
let plugin_list: [(
&str,
PluginShellType,
PluginProbeType,
Option<PluginValidator>,
); 3] = [
(
"atuin",
PluginShellType::Any,
PluginProbeType::EnvironmentVariable("ATUIN_SESSION"),
None,
),
(
"blesh",
PluginShellType::Bash,
PluginProbeType::EnvironmentVariable("BLE_SESSION_ID"),
Some(Self::validate_plugin_blesh),
),
(
"bash-preexec",
PluginShellType::Bash,
PluginProbeType::InteractiveShellVariable("bash_preexec_imported"),
None,
),
];
plugin_list
.into_iter()
.filter(|(_, shell_type, _, _)| match shell_type {
PluginShellType::Any => true,
PluginShellType::Bash => shell.starts_with("bash") || shell == "sh",
PluginShellType::Zsh => shell.starts_with("zsh"),
PluginShellType::Fish => shell.starts_with("fish"),
PluginShellType::Nushell => shell.starts_with("nu"),
PluginShellType::Xonsh => shell.starts_with("xonsh"),
})
.filter_map(|(plugin, _, probe_type, validator)| -> Option<String> {
match probe_type {
PluginProbeType::EnvironmentVariable(env) => {
env::var(env).ok().filter(|value| !value.is_empty())
}
PluginProbeType::InteractiveShellVariable(shellvar) => {
ShellInfo::shellvar_exists(shell, shellvar).then_some(String::default())
}
}
.and_then(|value| {
validator.map_or_else(
|| Some(plugin.to_string()),
|validator| validator(shell, shell_process, &value),
)
})
})
.collect()
}
pub fn new() -> Self {
// TODO: rework to use atuin_common::Shell
let sys = System::new_all();
let process = sys
.process(get_current_pid().expect("Failed to get current PID"))
.expect("Process with current pid does not exist");
let parent = sys
.process(process.parent().expect("Atuin running with no parent!"))
.expect("Process with parent pid does not exist");
let name = shell_name(Some(parent));
let plugins = ShellInfo::plugins(name.as_str(), parent);
let default = Shell::default_shell().unwrap_or(Shell::Unknown).to_string();
let preexec = Self::detect_preexec_framework(name.as_str());
Self {
name,
default,
plugins,
preexec,
}
}
}
#[derive(Debug, Serialize)]
struct DiskInfo {
pub name: String,
pub filesystem: String,
}
#[derive(Debug, Serialize)]
struct SystemInfo {
pub os: String,
pub arch: String,
pub version: String,
pub disks: Vec<DiskInfo>,
}
impl SystemInfo {
pub fn new() -> Self {
let disks = Disks::new_with_refreshed_list();
let disks = disks
.list()
.iter()
.map(|d| DiskInfo {
name: d.name().to_os_string().into_string().unwrap(),
filesystem: d.file_system().to_os_string().into_string().unwrap(),
})
.collect();
Self {
os: System::name().unwrap_or_else(|| "unknown".to_string()),
arch: System::cpu_arch().unwrap_or_else(|| "unknown".to_string()),
versi
gitextract_6o_czke4/
├── .cargo/
│ └── audit.toml
├── .codespellrc
├── .dockerignore
├── .gitattributes
├── .github/
│ ├── DISCUSSION_TEMPLATE/
│ │ └── support.yml
│ ├── FUNDING.yml
│ ├── ISSUE_TEMPLATE/
│ │ └── bug.yaml
│ ├── dependabot.yml
│ ├── pull_request_template.md
│ └── workflows/
│ ├── codespell.yml
│ ├── docker.yaml
│ ├── installer.yml
│ ├── nix.yml
│ ├── release.yml
│ ├── rust.yml
│ ├── shellcheck.yml
│ └── update-nix-deps.yml
├── .gitignore
├── .mailmap
├── .rustfmt.toml
├── AGENTS.md
├── CHANGELOG.md
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── CONTRIBUTORS
├── Cargo.toml
├── Dockerfile
├── LICENSE
├── README.md
├── atuin.nix
├── atuin.plugin.zsh
├── cliff.toml
├── crates/
│ ├── atuin/
│ │ ├── Cargo.toml
│ │ ├── LICENSE
│ │ ├── build.rs
│ │ ├── src/
│ │ │ ├── command/
│ │ │ │ ├── client/
│ │ │ │ │ ├── account/
│ │ │ │ │ │ ├── change_password.rs
│ │ │ │ │ │ ├── delete.rs
│ │ │ │ │ │ ├── link.rs
│ │ │ │ │ │ ├── login.rs
│ │ │ │ │ │ ├── logout.rs
│ │ │ │ │ │ └── register.rs
│ │ │ │ │ ├── account.rs
│ │ │ │ │ ├── daemon.rs
│ │ │ │ │ ├── default_config.rs
│ │ │ │ │ ├── doctor.rs
│ │ │ │ │ ├── dotfiles/
│ │ │ │ │ │ ├── alias.rs
│ │ │ │ │ │ └── var.rs
│ │ │ │ │ ├── dotfiles.rs
│ │ │ │ │ ├── history.rs
│ │ │ │ │ ├── import.rs
│ │ │ │ │ ├── info.rs
│ │ │ │ │ ├── init/
│ │ │ │ │ │ ├── bash.rs
│ │ │ │ │ │ ├── fish.rs
│ │ │ │ │ │ ├── powershell.rs
│ │ │ │ │ │ ├── xonsh.rs
│ │ │ │ │ │ └── zsh.rs
│ │ │ │ │ ├── init.rs
│ │ │ │ │ ├── kv.rs
│ │ │ │ │ ├── scripts.rs
│ │ │ │ │ ├── search/
│ │ │ │ │ │ ├── cursor.rs
│ │ │ │ │ │ ├── duration.rs
│ │ │ │ │ │ ├── engines/
│ │ │ │ │ │ │ ├── daemon.rs
│ │ │ │ │ │ │ ├── db.rs
│ │ │ │ │ │ │ └── skim.rs
│ │ │ │ │ │ ├── engines.rs
│ │ │ │ │ │ ├── history_list.rs
│ │ │ │ │ │ ├── inspector.rs
│ │ │ │ │ │ ├── interactive.rs
│ │ │ │ │ │ └── keybindings/
│ │ │ │ │ │ ├── actions.rs
│ │ │ │ │ │ ├── conditions.rs
│ │ │ │ │ │ ├── defaults.rs
│ │ │ │ │ │ ├── key.rs
│ │ │ │ │ │ ├── keymap.rs
│ │ │ │ │ │ └── mod.rs
│ │ │ │ │ ├── search.rs
│ │ │ │ │ ├── setup.rs
│ │ │ │ │ ├── stats.rs
│ │ │ │ │ ├── store/
│ │ │ │ │ │ ├── pull.rs
│ │ │ │ │ │ ├── purge.rs
│ │ │ │ │ │ ├── push.rs
│ │ │ │ │ │ ├── rebuild.rs
│ │ │ │ │ │ ├── rekey.rs
│ │ │ │ │ │ └── verify.rs
│ │ │ │ │ ├── store.rs
│ │ │ │ │ ├── sync/
│ │ │ │ │ │ └── status.rs
│ │ │ │ │ ├── sync.rs
│ │ │ │ │ └── wrapped.rs
│ │ │ │ ├── client.rs
│ │ │ │ ├── contributors.rs
│ │ │ │ ├── external.rs
│ │ │ │ ├── gen_completions.rs
│ │ │ │ └── mod.rs
│ │ │ ├── main.rs
│ │ │ ├── shell/
│ │ │ │ ├── .gitattributes
│ │ │ │ ├── atuin.bash
│ │ │ │ ├── atuin.fish
│ │ │ │ ├── atuin.nu
│ │ │ │ ├── atuin.ps1
│ │ │ │ ├── atuin.xsh
│ │ │ │ └── atuin.zsh
│ │ │ └── sync.rs
│ │ └── tests/
│ │ ├── common/
│ │ │ └── mod.rs
│ │ ├── sync.rs
│ │ └── users.rs
│ ├── atuin-ai/
│ │ ├── Cargo.toml
│ │ ├── render-tests.sh
│ │ ├── replay-states.sh
│ │ ├── src/
│ │ │ ├── commands/
│ │ │ │ ├── debug_render.rs
│ │ │ │ ├── init.rs
│ │ │ │ └── inline.rs
│ │ │ ├── commands.rs
│ │ │ ├── lib.rs
│ │ │ └── tui/
│ │ │ ├── app.rs
│ │ │ ├── component.rs
│ │ │ ├── components.rs
│ │ │ ├── event.rs
│ │ │ ├── mod.rs
│ │ │ ├── popup.rs
│ │ │ ├── render.rs
│ │ │ ├── spinner.rs
│ │ │ ├── state.rs
│ │ │ ├── terminal.rs
│ │ │ └── view_model.rs
│ │ └── test-renders.json
│ ├── atuin-client/
│ │ ├── Cargo.toml
│ │ ├── config.toml
│ │ ├── meta-migrations/
│ │ │ └── 20260203030924_create_meta.sql
│ │ ├── migrations/
│ │ │ ├── 20210422143411_create_history.sql
│ │ │ ├── 20220505083406_create-events.sql
│ │ │ ├── 20220806155627_interactive_search_index.sql
│ │ │ ├── 20230315220114_drop-events.sql
│ │ │ ├── 20230319185725_deleted_at.sql
│ │ │ └── 20260224000100_history_author_intent.sql
│ │ ├── record-migrations/
│ │ │ ├── 20230531212437_create-records.sql
│ │ │ └── 20231127090831_create-store.sql
│ │ ├── src/
│ │ │ ├── api_client.rs
│ │ │ ├── auth.rs
│ │ │ ├── database.rs
│ │ │ ├── distro.rs
│ │ │ ├── encryption.rs
│ │ │ ├── history/
│ │ │ │ ├── builder.rs
│ │ │ │ └── store.rs
│ │ │ ├── history.rs
│ │ │ ├── hub.rs
│ │ │ ├── import/
│ │ │ │ ├── bash.rs
│ │ │ │ ├── fish.rs
│ │ │ │ ├── mod.rs
│ │ │ │ ├── nu.rs
│ │ │ │ ├── nu_histdb.rs
│ │ │ │ ├── powershell.rs
│ │ │ │ ├── replxx.rs
│ │ │ │ ├── resh.rs
│ │ │ │ ├── xonsh.rs
│ │ │ │ ├── xonsh_sqlite.rs
│ │ │ │ ├── zsh.rs
│ │ │ │ └── zsh_histdb.rs
│ │ │ ├── lib.rs
│ │ │ ├── login.rs
│ │ │ ├── logout.rs
│ │ │ ├── meta.rs
│ │ │ ├── ordering.rs
│ │ │ ├── plugin.rs
│ │ │ ├── record/
│ │ │ │ ├── encryption.rs
│ │ │ │ ├── mod.rs
│ │ │ │ ├── sqlite_store.rs
│ │ │ │ ├── store.rs
│ │ │ │ └── sync.rs
│ │ │ ├── register.rs
│ │ │ ├── secrets.rs
│ │ │ ├── settings/
│ │ │ │ ├── dotfiles.rs
│ │ │ │ ├── kv.rs
│ │ │ │ ├── meta.rs
│ │ │ │ ├── scripts.rs
│ │ │ │ └── watcher.rs
│ │ │ ├── settings.rs
│ │ │ ├── sync.rs
│ │ │ ├── theme.rs
│ │ │ └── utils.rs
│ │ └── tests/
│ │ └── data/
│ │ └── xonsh/
│ │ ├── xonsh-82eafbf5-9f43-489a-80d2-61c7dc6ef542.json
│ │ └── xonsh-de16af90-9148-4461-8df3-5b5659c6420d.json
│ ├── atuin-common/
│ │ ├── Cargo.toml
│ │ └── src/
│ │ ├── api.rs
│ │ ├── calendar.rs
│ │ ├── lib.rs
│ │ ├── record.rs
│ │ ├── shell.rs
│ │ ├── tls.rs
│ │ └── utils.rs
│ ├── atuin-daemon/
│ │ ├── Cargo.toml
│ │ ├── build.rs
│ │ ├── proto/
│ │ │ ├── control.proto
│ │ │ ├── history.proto
│ │ │ └── search.proto
│ │ ├── src/
│ │ │ ├── client.rs
│ │ │ ├── components/
│ │ │ │ ├── history.rs
│ │ │ │ ├── mod.rs
│ │ │ │ ├── search.rs
│ │ │ │ └── sync.rs
│ │ │ ├── control/
│ │ │ │ ├── mod.rs
│ │ │ │ └── service.rs
│ │ │ ├── daemon.rs
│ │ │ ├── events.rs
│ │ │ ├── history/
│ │ │ │ └── mod.rs
│ │ │ ├── lib.rs
│ │ │ ├── search/
│ │ │ │ ├── index.rs
│ │ │ │ └── mod.rs
│ │ │ └── server.rs
│ │ └── tests/
│ │ └── lifecycle.rs
│ ├── atuin-dotfiles/
│ │ ├── Cargo.toml
│ │ └── src/
│ │ ├── lib.rs
│ │ ├── shell/
│ │ │ ├── bash.rs
│ │ │ ├── fish.rs
│ │ │ ├── powershell.rs
│ │ │ ├── xonsh.rs
│ │ │ └── zsh.rs
│ │ ├── shell.rs
│ │ ├── store/
│ │ │ ├── alias.rs
│ │ │ └── var.rs
│ │ └── store.rs
│ ├── atuin-hex/
│ │ ├── Cargo.toml
│ │ └── src/
│ │ ├── lib.rs
│ │ └── osc133.rs
│ ├── atuin-history/
│ │ ├── Cargo.toml
│ │ ├── benches/
│ │ │ └── smart_sort.rs
│ │ └── src/
│ │ ├── lib.rs
│ │ ├── sort.rs
│ │ └── stats.rs
│ ├── atuin-kv/
│ │ ├── Cargo.toml
│ │ ├── migrations/
│ │ │ ├── 20250501160746_create_kv_db.down.sql
│ │ │ └── 20250501160746_create_kv_db.up.sql
│ │ └── src/
│ │ ├── database.rs
│ │ ├── lib.rs
│ │ ├── store/
│ │ │ ├── entry.rs
│ │ │ └── record.rs
│ │ └── store.rs
│ ├── atuin-nucleo/
│ │ ├── .gitignore
│ │ ├── CHANGELOG.md
│ │ ├── Cargo.toml
│ │ ├── LICENSE
│ │ ├── README.md
│ │ ├── bench/
│ │ │ ├── Cargo.toml
│ │ │ └── src/
│ │ │ └── main.rs
│ │ ├── matcher/
│ │ │ ├── Cargo.toml
│ │ │ ├── fuzz/
│ │ │ │ ├── .gitignore
│ │ │ │ ├── Cargo.toml
│ │ │ │ └── fuzz_targets/
│ │ │ │ └── fuzz_target_1.rs
│ │ │ ├── fuzz.sh
│ │ │ ├── generate_case_fold_table.sh
│ │ │ └── src/
│ │ │ ├── chars/
│ │ │ │ ├── case_fold.rs
│ │ │ │ └── normalize.rs
│ │ │ ├── chars.rs
│ │ │ ├── config.rs
│ │ │ ├── debug.rs
│ │ │ ├── exact.rs
│ │ │ ├── fuzzy_greedy.rs
│ │ │ ├── fuzzy_optimal.rs
│ │ │ ├── lib.rs
│ │ │ ├── matrix.rs
│ │ │ ├── pattern/
│ │ │ │ └── tests.rs
│ │ │ ├── pattern.rs
│ │ │ ├── prefilter.rs
│ │ │ ├── score.rs
│ │ │ ├── tests.rs
│ │ │ ├── utf32_str/
│ │ │ │ └── tests.rs
│ │ │ └── utf32_str.rs
│ │ ├── src/
│ │ │ ├── boxcar.rs
│ │ │ ├── lib.rs
│ │ │ ├── par_sort.rs
│ │ │ ├── pattern/
│ │ │ │ └── tests.rs
│ │ │ ├── pattern.rs
│ │ │ ├── tests.rs
│ │ │ └── worker.rs
│ │ ├── tarpaulin.toml
│ │ └── typos.toml
│ ├── atuin-scripts/
│ │ ├── Cargo.toml
│ │ ├── migrations/
│ │ │ ├── 20250326160051_create_scripts.down.sql
│ │ │ ├── 20250326160051_create_scripts.up.sql
│ │ │ ├── 20250402170430_unique_names.down.sql
│ │ │ └── 20250402170430_unique_names.up.sql
│ │ └── src/
│ │ ├── database.rs
│ │ ├── execution.rs
│ │ ├── lib.rs
│ │ ├── settings.rs
│ │ ├── store/
│ │ │ ├── record.rs
│ │ │ └── script.rs
│ │ └── store.rs
│ ├── atuin-server/
│ │ ├── Cargo.toml
│ │ ├── server.toml
│ │ └── src/
│ │ ├── bin/
│ │ │ └── main.rs
│ │ ├── handlers/
│ │ │ ├── health.rs
│ │ │ ├── history.rs
│ │ │ ├── mod.rs
│ │ │ ├── record.rs
│ │ │ ├── status.rs
│ │ │ ├── user.rs
│ │ │ └── v0/
│ │ │ ├── me.rs
│ │ │ ├── mod.rs
│ │ │ ├── record.rs
│ │ │ └── store.rs
│ │ ├── lib.rs
│ │ ├── metrics.rs
│ │ ├── router.rs
│ │ ├── settings.rs
│ │ └── utils.rs
│ ├── atuin-server-database/
│ │ ├── Cargo.toml
│ │ └── src/
│ │ ├── calendar.rs
│ │ ├── lib.rs
│ │ └── models.rs
│ ├── atuin-server-postgres/
│ │ ├── Cargo.toml
│ │ ├── build.rs
│ │ ├── migrations/
│ │ │ ├── 20210425153745_create_history.sql
│ │ │ ├── 20210425153757_create_users.sql
│ │ │ ├── 20210425153800_create_sessions.sql
│ │ │ ├── 20220419082412_add_count_trigger.sql
│ │ │ ├── 20220421073605_fix_count_trigger_delete.sql
│ │ │ ├── 20220421174016_larger-commands.sql
│ │ │ ├── 20220426172813_user-created-at.sql
│ │ │ ├── 20220505082442_create-events.sql
│ │ │ ├── 20220610074049_history-length.sql
│ │ │ ├── 20230315220537_drop-events.sql
│ │ │ ├── 20230315224203_create-deleted.sql
│ │ │ ├── 20230515221038_trigger-delete-only.sql
│ │ │ ├── 20230623070418_records.sql
│ │ │ ├── 20231202170508_create-store.sql
│ │ │ ├── 20231203124112_create-store-idx.sql
│ │ │ ├── 20240108124837_drop-some-defaults.sql
│ │ │ ├── 20240614104159_idx-cache.sql
│ │ │ ├── 20240621110731_user-verified.sql
│ │ │ ├── 20240702094825_idx_cache_index.sql
│ │ │ └── 20260127000000_remove-email-verification.sql
│ │ └── src/
│ │ ├── lib.rs
│ │ └── wrappers.rs
│ └── atuin-server-sqlite/
│ ├── Cargo.toml
│ ├── build.rs
│ ├── migrations/
│ │ ├── 20231203124112_create-store.sql
│ │ ├── 20240108124830_create-history.sql
│ │ ├── 20240108124831_create-sessions.sql
│ │ ├── 20240621110730_create-users.sql
│ │ ├── 20240621110731_create-user-verification-token.sql
│ │ ├── 20240702094825_create-store-idx-cache.sql
│ │ └── 20260127000000_remove-email-verification.sql
│ └── src/
│ ├── lib.rs
│ └── wrappers.rs
├── default.nix
├── deny.toml
├── depot.json
├── dist-workspace.toml
├── docker-compose.yml
├── docs/
│ ├── .gitignore
│ ├── docs/
│ │ ├── ai/
│ │ │ ├── introduction.md
│ │ │ └── settings.md
│ │ ├── configuration/
│ │ │ ├── advanced-key-binding.md
│ │ │ ├── config.md
│ │ │ └── key-binding.md
│ │ ├── faq.md
│ │ ├── guide/
│ │ │ ├── advanced-usage.md
│ │ │ ├── basic-usage.md
│ │ │ ├── delete-history.md
│ │ │ ├── dotfiles.md
│ │ │ ├── getting-started.md
│ │ │ ├── import.md
│ │ │ ├── installation.md
│ │ │ ├── shell-integration.md
│ │ │ ├── sync.md
│ │ │ └── theming.md
│ │ ├── index.md
│ │ ├── integrations.md
│ │ ├── known-issues.md
│ │ ├── reference/
│ │ │ ├── daemon.md
│ │ │ ├── doctor.md
│ │ │ ├── gen-completions.md
│ │ │ ├── import.md
│ │ │ ├── info.md
│ │ │ ├── list.md
│ │ │ ├── prune.md
│ │ │ ├── search.md
│ │ │ ├── stats.md
│ │ │ └── sync.md
│ │ ├── self-hosting/
│ │ │ ├── docker.md
│ │ │ ├── kubernetes.md
│ │ │ ├── server-setup.md
│ │ │ ├── systemd.md
│ │ │ └── usage.md
│ │ ├── sync-v2.md
│ │ └── uninstall.md
│ ├── mkdocs.yml
│ └── pyproject.toml
├── docs-i18n/
│ ├── .gitignore
│ ├── ru/
│ │ ├── config_ru.md
│ │ ├── import_ru.md
│ │ ├── key-binding_ru.md
│ │ ├── list_ru.md
│ │ ├── search_ru.md
│ │ ├── server_ru.md
│ │ ├── shell-completions_ru.md
│ │ ├── stats_ru.md
│ │ └── sync_ru.md
│ └── zh-CN/
│ ├── README.md
│ ├── config.md
│ ├── docker.md
│ ├── import.md
│ ├── k8s.md
│ ├── key-binding.md
│ ├── list.md
│ ├── search.md
│ ├── server.md
│ ├── shell-completions.md
│ ├── stats.md
│ └── sync.md
├── flake.nix
├── install.sh
├── k8s/
│ ├── atuin.yaml
│ ├── namespaces.yaml
│ └── secrets.yaml
├── rust-toolchain.toml
├── scripts/
│ └── span-table.ts
└── systemd/
├── atuin-server.service
└── atuin-server.sysusers
Showing preview only (218K chars total). Download the full file or copy to clipboard to get everything.
SYMBOL INDEX (2615 symbols across 237 files)
FILE: crates/atuin-ai/src/commands.rs
type AiArgs (line 18) | pub struct AiArgs {
type Commands (line 33) | pub enum Commands {
function run (line 76) | pub async fn run(
function detect_shell (line 117) | pub fn detect_shell() -> Option<String> {
function init_logging (line 122) | fn init_logging(settings: &atuin_client::settings::Settings, verbose: bo...
function cleanup_old_logs (line 175) | fn cleanup_old_logs(log_dir: &Path, prefix: &str, retention_days: u64) {
FILE: crates/atuin-ai/src/commands/debug_render.rs
type DebugInput (line 20) | pub struct DebugInput {
method from_json (line 117) | pub fn from_json(json: &str) -> Result<Self> {
method to_state (line 122) | pub fn to_state(&self) -> AppState {
function default_mode (line 58) | fn default_mode() -> String {
function default_width (line 62) | fn default_width() -> u16 {
function default_height (line 66) | fn default_height() -> u16 {
type EventInput (line 74) | pub enum EventInput {
method from (line 95) | fn from(input: EventInput) -> Self {
type OutputFormat (line 172) | pub enum OutputFormat {
function run (line 183) | pub async fn run(input_file: Option<String>, format: OutputFormat) -> Re...
function blocks_to_json (line 241) | fn blocks_to_json(blocks: &Blocks) -> serde_json::Value {
function content_to_json (line 258) | fn content_to_json(content: &crate::tui::view_model::Content) -> serde_j...
function buffer_to_string (line 313) | fn buffer_to_string(buffer: &ratatui::buffer::Buffer, strip_ansi: bool) ...
function color_to_ansi (line 396) | fn color_to_ansi(color: ratatui::style::Color, foreground: bool) -> Opti...
function test_parse_simple_input (line 433) | fn test_parse_simple_input() {
function test_parse_streaming_state (line 452) | fn test_parse_streaming_state() {
FILE: crates/atuin-ai/src/commands/init.rs
function run (line 3) | pub async fn run(shell: String) -> eyre::Result<()> {
function generate_auto_integration (line 16) | fn generate_auto_integration() -> eyre::Result<&'static str> {
function generate_zsh_integration (line 28) | pub fn generate_zsh_integration() -> &'static str {
function generate_bash_integration (line 82) | pub fn generate_bash_integration() -> &'static str {
function generate_fish_integration (line 143) | pub fn generate_fish_integration() -> &'static str {
function test_generate_zsh_integration (line 196) | fn test_generate_zsh_integration() {
function test_generate_bash_integration (line 209) | fn test_generate_bash_integration() {
function test_generate_fish_integration (line 222) | fn test_generate_fish_integration() {
FILE: crates/atuin-ai/src/commands/inline.rs
function run (line 21) | pub async fn run(
function ensure_hub_session (line 82) | async fn ensure_hub_session(settings: &atuin_client::settings::Settings)...
type ChatStreamEvent (line 145) | enum ChatStreamEvent {
function create_chat_stream (line 168) | fn create_chat_stream(
function hub_url (line 327) | fn hub_url(base: &str, path: &str) -> Result<Url> {
function detect_os (line 339) | fn detect_os() -> String {
type Action (line 349) | enum Action {
function state_to_json (line 357) | fn state_to_json(state: &crate::tui::AppState) -> serde_json::Value {
type DebugStateLogger (line 397) | struct DebugStateLogger {
method new (line 404) | fn new(path: &str) -> Result<Self> {
method log (line 416) | fn log(&mut self, label: &str, state: &crate::tui::AppState) {
function run_inline_tui (line 448) | async fn run_inline_tui(
type RawModeGuard (line 717) | struct RawModeGuard;
method drop (line 720) | fn drop(&mut self) {
function emit_shell_result (line 725) | fn emit_shell_result(action: Action, output_for_hook: bool) {
function wait_for_login_confirmation (line 743) | fn wait_for_login_confirmation() -> Result<bool> {
FILE: crates/atuin-ai/src/tui/app.rs
type App (line 7) | pub struct App {
method new (line 12) | pub fn new() -> Self {
method handle_key (line 19) | pub fn handle_key(&mut self, key: KeyEvent) -> bool {
method handle_input_key (line 29) | fn handle_input_key(&mut self, key: KeyEvent) -> bool {
method handle_generating_key (line 78) | fn handle_generating_key(&mut self, key: KeyEvent) -> bool {
method handle_streaming_key (line 88) | fn handle_streaming_key(&mut self, key: KeyEvent) -> bool {
method handle_review_key (line 98) | fn handle_review_key(&mut self, key: KeyEvent) -> bool {
method handle_error_key (line 138) | fn handle_error_key(&mut self, key: KeyEvent) -> bool {
method default (line 154) | fn default() -> Self {
FILE: crates/atuin-ai/src/tui/component.rs
type RenderContext (line 13) | pub struct RenderContext<'a> {
type Component (line 29) | pub trait Component {
method height (line 31) | fn height(&self, width: u16) -> u16;
method render (line 34) | fn render(&self, frame: &mut Frame, area: Rect, ctx: &RenderContext);
method height (line 59) | fn height(&self, width: u16) -> u16 {
method render (line 68) | fn render(&self, frame: &mut Frame, area: Rect, ctx: &RenderContext) {
method height (line 110) | fn height(&self, _width: u16) -> u16 {
method render (line 114) | fn render(&self, _frame: &mut Frame, _area: Rect, _ctx: &RenderContext...
method height (line 128) | fn height(&self, width: u16) -> u16 {
method render (line 132) | fn render(&self, frame: &mut Frame, area: Rect, ctx: &RenderContext) {
method height (line 165) | fn height(&self, _width: u16) -> u16 {
method render (line 169) | fn render(&self, frame: &mut Frame, area: Rect, ctx: &RenderContext) {
type VStack (line 42) | pub struct VStack {
method new (line 49) | pub fn new(children: Vec<Box<dyn Component>>) -> Self {
type Spacer (line 107) | pub struct Spacer(pub u16);
type SymbolRow (line 121) | pub struct SymbolRow {
type Separator (line 160) | pub struct Separator {
FILE: crates/atuin-ai/src/tui/components.rs
function line_count_wrapped (line 24) | pub(crate) fn line_count_wrapped(text: &str, width: usize) -> u16 {
function word_wrap_line_count_with_last_width (line 35) | pub(crate) fn word_wrap_line_count_with_last_width(text: &str, width: us...
function style_inline_markdown (line 108) | fn style_inline_markdown(text: &str, theme: &Theme) -> Vec<Line<'static>> {
function parse_inline_formatting (line 123) | fn parse_inline_formatting(
type InputContent (line 197) | pub struct InputContent {
method height (line 203) | fn height(&self, width: u16) -> u16 {
method render (line 217) | fn render(&self, frame: &mut Frame, area: Rect, ctx: &RenderContext) {
type CommandContent (line 235) | pub struct CommandContent {
method height (line 241) | fn height(&self, width: u16) -> u16 {
method render (line 245) | fn render(&self, frame: &mut Frame, area: Rect, ctx: &RenderContext) {
type TextContent (line 260) | pub struct TextContent {
method height (line 265) | fn height(&self, width: u16) -> u16 {
method render (line 272) | fn render(&self, frame: &mut Frame, area: Rect, ctx: &RenderContext) {
type ErrorContent (line 280) | pub struct ErrorContent {
method height (line 285) | fn height(&self, width: u16) -> u16 {
method render (line 289) | fn render(&self, frame: &mut Frame, area: Rect, ctx: &RenderContext) {
type WarningContent (line 301) | pub struct WarningContent {
method height (line 308) | fn height(&self, width: u16) -> u16 {
method render (line 317) | fn render(&self, frame: &mut Frame, area: Rect, ctx: &RenderContext) {
type SpinnerContent (line 334) | pub struct SpinnerContent {
method height (line 339) | fn height(&self, _width: u16) -> u16 {
method render (line 343) | fn render(&self, frame: &mut Frame, area: Rect, ctx: &RenderContext) {
type ToolStatusContent (line 350) | pub struct ToolStatusContent {
method height (line 357) | fn height(&self, _width: u16) -> u16 {
method render (line 361) | fn render(&self, frame: &mut Frame, area: Rect, ctx: &RenderContext) {
function content_to_component (line 390) | fn content_to_component(content: &Content) -> Box<dyn Component> {
function build_block_component (line 478) | fn build_block_component(block: &Block) -> Box<dyn Component> {
function build_component_tree (line 498) | pub fn build_component_tree(items: &[&Block], card_width: u16) -> VStack {
FILE: crates/atuin-ai/src/tui/event.rs
constant BASE_TICK_INTERVAL (line 9) | const BASE_TICK_INTERVAL: Duration = Duration::from_millis(50);
type AppEvent (line 24) | pub enum AppEvent {
type EventLoop (line 73) | pub struct EventLoop {
method new (line 92) | pub fn new() -> Self {
method run (line 136) | pub async fn run(&mut self) -> Result<AppEvent> {
method is_shutdown (line 220) | pub fn is_shutdown(&self) -> bool {
method shutdown (line 227) | pub fn shutdown(&mut self) {
method poll_and_apply (line 249) | pub async fn poll_and_apply(&mut self, app: &mut App) -> Result<bool> {
method default (line 272) | fn default() -> Self {
function test_event_loop_creation (line 282) | fn test_event_loop_creation() {
function test_shutdown_flag (line 288) | fn test_shutdown_flag() {
FILE: crates/atuin-ai/src/tui/popup.rs
constant MAX_POPUP_HEIGHT (line 4) | const MAX_POPUP_HEIGHT: u16 = 24;
constant MIN_POPUP_HEIGHT (line 7) | const MIN_POPUP_HEIGHT: u16 = 5;
constant INITIAL_POPUP_HEIGHT (line 10) | const INITIAL_POPUP_HEIGHT: u16 = 5;
constant POPUP_MARGIN (line 13) | pub(crate) const POPUP_MARGIN: u16 = 0;
type SavedScreen (line 16) | pub struct SavedScreen {
type PopupState (line 28) | pub struct PopupState {
method fit_to (line 48) | pub fn fit_to(&mut self, needed: u16) -> Option<Rect> {
method clear_rows (line 85) | fn clear_rows(&self, from_row: u16, to_row: u16) {
method restore_rows (line 110) | fn restore_rows(&self, old_rect: &Rect) {
function try_setup_popup (line 153) | pub fn try_setup_popup() -> Option<PopupState> {
function restore (line 208) | pub fn restore(state: &PopupState) {
function fetch_screen_state (line 259) | fn fetch_screen_state(socket_path: &str) -> Option<SavedScreen> {
function compute_popup_placement (line 313) | fn compute_popup_placement(
FILE: crates/atuin-ai/src/tui/render.rs
constant CARD_WIDTH (line 20) | pub(crate) const CARD_WIDTH: u16 = 64;
function calculate_needed_height (line 25) | pub fn calculate_needed_height(state: &AppState, card_width: u16) -> u16 {
function render (line 42) | pub fn render(frame: &mut Frame, state: &AppState, ctx: &RenderContext) {
function render_view (line 50) | fn render_view(frame: &mut Frame, view: &Blocks, ctx: &RenderContext) {
function markdown_to_spans (line 143) | pub fn markdown_to_spans<'a>(text: &'a str, theme: &'a Theme) -> Vec<Lin...
FILE: crates/atuin-ai/src/tui/spinner.rs
constant ACTIVE_SPINNER (line 8) | pub const ACTIVE_SPINNER: SpinnerStyle = SpinnerStyle::Dots;
type SpinnerStyle (line 12) | pub enum SpinnerStyle {
method frames (line 27) | pub const fn frames(&self) -> &'static [&'static str] {
method tick_interval (line 41) | pub const fn tick_interval(&self) -> Duration {
method frame_at (line 52) | pub fn frame_at(&self, index: usize) -> &'static str {
method frame_count (line 58) | pub fn frame_count(&self) -> usize {
function active_frame (line 64) | pub fn active_frame(index: usize) -> &'static str {
function active_tick_interval (line 69) | pub fn active_tick_interval() -> Duration {
function test_frame_wrapping (line 78) | fn test_frame_wrapping() {
function test_all_styles_have_frames (line 86) | fn test_all_styles_have_frames() {
FILE: crates/atuin-ai/src/tui/state.rs
type StreamingStatus (line 13) | pub enum StreamingStatus {
method from_status_str (line 21) | pub fn from_status_str(s: &str) -> Self {
method display_text (line 30) | pub fn display_text(&self) -> &'static str {
type ConversationEvent (line 42) | pub enum ConversationEvent {
method to_json (line 63) | pub fn to_json(&self) -> serde_json::Value {
method as_command (line 93) | pub fn as_command(&self) -> Option<&str> {
type AppMode (line 105) | pub enum AppMode {
type ExitAction (line 119) | pub enum ExitAction {
type AppState (line 132) | pub struct AppState {
method new (line 174) | pub fn new() -> Self {
method input (line 194) | pub fn input(&self) -> String {
method input_is_empty (line 199) | pub fn input_is_empty(&self) -> bool {
method clear_input (line 204) | pub fn clear_input(&mut self) {
method events_to_messages (line 210) | pub fn events_to_messages(&self) -> Vec<serde_json::Value> {
method start_generating (line 277) | pub fn start_generating(&mut self) {
method generation_complete (line 289) | pub fn generation_complete(
method generation_error (line 330) | pub fn generation_error(&mut self, error: String) {
method cancel_generation (line 336) | pub fn cancel_generation(&mut self) {
method start_streaming (line 348) | pub fn start_streaming(&mut self) {
method store_session_id (line 357) | pub fn store_session_id(&mut self, session_id: String) {
method update_streaming_status (line 362) | pub fn update_streaming_status(&mut self, status: &str) {
method cancel_streaming (line 367) | pub fn cancel_streaming(&mut self) {
method append_streaming_text (line 390) | pub fn append_streaming_text(&mut self, chunk: &str) {
method add_tool_call (line 406) | pub fn add_tool_call(&mut self, id: String, name: String, input: serde...
method add_tool_result (line 430) | pub fn add_tool_result(&mut self, tool_use_id: String, content: String...
method finalize_streaming (line 439) | pub fn finalize_streaming(&mut self) {
method streaming_error (line 455) | pub fn streaming_error(&mut self, error: String) {
method start_edit_mode (line 466) | pub fn start_edit_mode(&mut self) {
method exit (line 473) | pub fn exit(&mut self, action: ExitAction) {
method retry (line 479) | pub fn retry(&mut self) {
method tick (line 489) | pub fn tick(&mut self) {
method current_command (line 498) | pub fn current_command(&self) -> Option<&str> {
method is_current_command_dangerous (line 504) | pub fn is_current_command_dangerous(&self) -> bool {
function create_textarea (line 164) | fn create_textarea() -> TextArea<'static> {
method default (line 527) | fn default() -> Self {
FILE: crates/atuin-ai/src/tui/terminal.rs
function install_panic_hook (line 20) | pub fn install_panic_hook() {
constant MIN_VIEWPORT_HEIGHT (line 31) | const MIN_VIEWPORT_HEIGHT: u16 = 10;
constant VIEWPORT_BOTTOM_MARGIN (line 34) | const VIEWPORT_BOTTOM_MARGIN: u16 = 2;
type TerminalGuard (line 63) | pub struct TerminalGuard {
method new (line 90) | pub fn new(keep_output: bool) -> Result<Self> {
method new_popup (line 137) | pub fn new_popup(popup_rect: Rect, anchor_col: u16) -> Result<Self> {
method ensure_height (line 187) | pub fn ensure_height(&mut self, _needed: u16) -> Result<u16> {
method viewport_height (line 192) | pub fn viewport_height(&self) -> u16 {
method terminal (line 199) | pub fn terminal(&mut self) -> &mut Terminal<CrosstermBackend<Stdout>> {
method resize_popup (line 208) | pub fn resize_popup(&mut self, new_rect: Rect) -> Result<()> {
method anchor_col (line 225) | pub fn anchor_col(&self) -> u16 {
method drop (line 244) | fn drop(&mut self) {
function test_panic_hook_installation (line 266) | fn test_panic_hook_installation() {
FILE: crates/atuin-ai/src/tui/view_model.rs
type WarningKind (line 11) | pub enum WarningKind {
type Content (line 20) | pub enum Content {
method prefix_symbol (line 60) | pub fn prefix_symbol(&self) -> &'static str {
type Block (line 84) | pub struct Block {
type StatusBar (line 92) | pub struct StatusBar {
type Blocks (line 101) | pub struct Blocks {
method from_state (line 158) | pub fn from_state(state: &AppState) -> Self {
method footer_for_mode (line 393) | fn footer_for_mode(
function count_tool_calls_since_last_user (line 109) | fn count_tool_calls_since_last_user(events: &[ConversationEvent]) -> (us...
function has_any_command (line 143) | fn has_any_command(events: &[ConversationEvent]) -> bool {
FILE: crates/atuin-client/meta-migrations/20260203030924_create_meta.sql
type meta (line 1) | create table if not exists meta (
FILE: crates/atuin-client/migrations/20210422143411_create_history.sql
type history (line 2) | create table if not exists history (
type idx_history_timestamp (line 15) | create index if not exists idx_history_timestamp on history(timestamp)
type idx_history_command (line 16) | create index if not exists idx_history_command on history(command)
FILE: crates/atuin-client/migrations/20220505083406_create-events.sql
type events (line 1) | create table if not exists events (
type history_event_idx (line 11) | create unique index history_event_idx ON events(event_type, history_id)
FILE: crates/atuin-client/migrations/20220806155627_interactive_search_index.sql
type idx_history_command_timestamp (line 3) | create index if not exists idx_history_command_timestamp on history(
FILE: crates/atuin-client/record-migrations/20230531212437_create-records.sql
type records (line 2) | create table if not exists records (
type host_idx (line 14) | create index host_idx on records (host)
type tag_idx (line 15) | create index tag_idx on records (tag)
type host_tag_idx (line 16) | create index host_tag_idx on records (host, tag)
FILE: crates/atuin-client/record-migrations/20231127090831_create-store.sql
type store (line 2) | create table if not exists store (
type record_uniq (line 15) | create unique index record_uniq ON store(host, tag, idx)
FILE: crates/atuin-client/src/api_client.rs
type AuthToken (line 42) | pub enum AuthToken {
method to_header_value (line 51) | fn to_header_value(&self) -> String {
type Client (line 59) | pub struct Client<'a> {
function make_url (line 64) | fn make_url(address: &str, path: &str) -> Result<String> {
function register (line 83) | pub async fn register(
function login (line 121) | pub async fn login(address: &str, req: LoginRequest) -> Result<LoginResp...
function latest_version (line 143) | pub async fn latest_version() -> Result<Version> {
function ensure_version (line 163) | pub fn ensure_version(response: &Response) -> Result<bool> {
function handle_resp_error (line 189) | async fn handle_resp_error(resp: Response) -> Result<Response> {
function new (line 225) | pub fn new(
function count (line 249) | pub async fn count(&self) -> Result<i64> {
function status (line 269) | pub async fn status(&self) -> Result<StatusResponse> {
function me (line 285) | pub async fn me(&self) -> Result<MeResponse> {
function get_history (line 297) | pub async fn get_history(
function post_history (line 322) | pub async fn post_history(&self, history: &[AddHistoryRequest]) -> Resul...
function delete_history (line 332) | pub async fn delete_history(&self, h: History) -> Result<()> {
function delete_store (line 350) | pub async fn delete_store(&self) -> Result<()> {
function post_records (line 361) | pub async fn post_records(&self, records: &[Record<EncryptedData>]) -> R...
function next_records (line 373) | pub async fn next_records(
function record_status (line 400) | pub async fn record_status(&self) -> Result<RecordStatus> {
function delete (line 418) | pub async fn delete(&self) -> Result<()> {
function change_password (line 433) | pub async fn change_password(
FILE: crates/atuin-client/src/auth.rs
type AuthResponse (line 19) | pub enum AuthResponse {
type MutateResponse (line 28) | pub enum MutateResponse {
type AuthClient (line 41) | pub trait AuthClient: Send + Sync {
method login (line 43) | async fn login(
method register (line 51) | async fn register(&self, username: &str, email: &str, password: &str) ...
method change_password (line 54) | async fn change_password(
method delete_account (line 62) | async fn delete_account(
method login (line 138) | async fn login(
method register (line 159) | async fn register(&self, username: &str, email: &str, password: &str) ...
method change_password (line 166) | async fn change_password(
method delete_account (line 192) | async fn delete_account(
method login (line 243) | async fn login(
method register (line 295) | async fn register(&self, username: &str, email: &str, password: &str) ...
method change_password (line 329) | async fn change_password(
method delete_account (line 383) | async fn delete_account(
function auth_client (line 70) | pub async fn auth_client(settings: &Settings) -> Box<dyn AuthClient> {
type LegacyAuthClient (line 91) | pub struct LegacyAuthClient {
method new (line 99) | pub fn new(
method authenticated_client (line 113) | fn authenticated_client(&self) -> Result<reqwest::Client> {
type HubAuthClient (line 219) | pub struct HubAuthClient {
method new (line 225) | pub fn new(address: &str, hub_token: Option<String>) -> Self {
type HubErrorResponse (line 236) | struct HubErrorResponse {
function make_url (line 440) | fn make_url(address: &str, path: &str) -> Result<String> {
FILE: crates/atuin-client/src/database.rs
type Context (line 36) | pub struct Context {
method from_history (line 77) | pub fn from_history(entry: &History) -> Self {
type OptFilters (line 45) | pub struct OptFilters {
function current_context (line 58) | pub async fn current_context() -> eyre::Result<Context> {
function get_session_start_time (line 88) | fn get_session_start_time(session_id: &str) -> Option<i64> {
type Database (line 99) | pub trait Database: Send + Sync + 'static {
method save (line 100) | async fn save(&self, h: &History) -> Result<()>;
method save_bulk (line 101) | async fn save_bulk(&self, h: &[History]) -> Result<()>;
method load (line 103) | async fn load(&self, id: &str) -> Result<Option<History>>;
method list (line 104) | async fn list(
method range (line 112) | async fn range(&self, from: OffsetDateTime, to: OffsetDateTime) -> Res...
method update (line 114) | async fn update(&self, h: &History) -> Result<()>;
method history_count (line 115) | async fn history_count(&self, include_deleted: bool) -> Result<i64>;
method last (line 117) | async fn last(&self) -> Result<Option<History>>;
method before (line 118) | async fn before(&self, timestamp: OffsetDateTime, count: i64) -> Resul...
method delete (line 120) | async fn delete(&self, h: History) -> Result<()>;
method delete_rows (line 121) | async fn delete_rows(&self, ids: &[HistoryId]) -> Result<()>;
method deleted (line 122) | async fn deleted(&self) -> Result<Vec<History>>;
method search (line 128) | async fn search(
method query_history (line 137) | async fn query_history(&self, query: &str) -> Result<Vec<History>>;
method all_with_count (line 139) | async fn all_with_count(&self) -> Result<Vec<(History, i32)>>;
method all_paged (line 141) | fn all_paged(&self, page_size: usize, include_deleted: bool, unique: b...
method stats (line 143) | async fn stats(&self, h: &History) -> Result<HistoryStats>;
method get_dups (line 145) | async fn get_dups(&self, before: i64, dupkeep: u32) -> Result<Vec<Hist...
method clone_boxed (line 147) | fn clone_boxed(&self) -> Box<dyn Database + 'static>;
method save (line 273) | async fn save(&self, h: &History) -> Result<()> {
method save_bulk (line 282) | async fn save_bulk(&self, h: &[History]) -> Result<()> {
method load (line 296) | async fn load(&self, id: &str) -> Result<Option<History>> {
method update (line 308) | async fn update(&self, h: &History) -> Result<()> {
method list (line 334) | async fn list(
method range (line 393) | async fn range(&self, from: OffsetDateTime, to: OffsetDateTime) -> Res...
method last (line 408) | async fn last(&self) -> Result<Option<History>> {
method before (line 419) | async fn before(&self, timestamp: OffsetDateTime, count: i64) -> Resul...
method deleted (line 432) | async fn deleted(&self) -> Result<Vec<History>> {
method history_count (line 441) | async fn history_count(&self, include_deleted: bool) -> Result<i64> {
method search (line 452) | async fn search(
method query_history (line 610) | async fn query_history(&self, query: &str) -> Result<Vec<History>> {
method all_with_count (line 619) | async fn all_with_count(&self) -> Result<Vec<(History, i32)>> {
method all_paged (line 657) | fn all_paged(&self, page_size: usize, include_deleted: bool, unique: b...
method delete (line 663) | async fn delete(&self, mut h: History) -> Result<()> {
method delete_rows (line 677) | async fn delete_rows(&self, ids: &[HistoryId]) -> Result<()> {
method stats (line 689) | async fn stats(&self, h: &History) -> Result<HistoryStats> {
method get_dups (line 806) | async fn get_dups(&self, before: i64, dupkeep: u32) -> Result<Vec<Hist...
method clone_boxed (line 826) | fn clone_boxed(&self) -> Box<dyn Database + 'static> {
type Sqlite (line 153) | pub struct Sqlite {
method new (line 158) | pub async fn new(path: impl AsRef<Path>, timeout: f64) -> Result<Self> {
method sqlite_version (line 191) | pub async fn sqlite_version(&self) -> Result<String> {
method setup_db (line 197) | async fn setup_db(pool: &SqlitePool) -> Result<()> {
method save_raw (line 205) | async fn save_raw(tx: &mut sqlx::Transaction<'_, sqlx::Sqlite>, h: &Hi...
method delete_row_raw (line 227) | async fn delete_row_raw(
method query_history (line 239) | fn query_history(row: SqliteRow) -> History {
type Paged (line 831) | pub struct Paged {
method new (line 840) | pub fn new(
method next (line 855) | pub async fn next(&mut self) -> Result<Option<Vec<History>>> {
type SqlBuilderExt (line 891) | trait SqlBuilderExt {
method fuzzy_condition (line 892) | fn fuzzy_condition<S: ToString, T: ToString>(
method fuzzy_condition (line 904) | fn fuzzy_condition<S: ToString, T: ToString>(
function assert_search_eq (line 938) | async fn assert_search_eq(
function assert_search_commands (line 975) | async fn assert_search_commands(
function new_history_item (line 989) | async fn new_history_item(db: &mut impl Database, cmd: &str) -> Result<(...
function test_search_prefix (line 1006) | async fn test_search_prefix() {
function test_search_fulltext (line 1024) | async fn test_search_fulltext() {
function test_search_fuzzy (line 1110) | async fn test_search_fuzzy() {
function test_search_reordered_fuzzy (line 1213) | async fn test_search_reordered_fuzzy() {
function test_paged_basic (line 1241) | async fn test_paged_basic() {
function test_paged_empty (line 1277) | async fn test_paged_empty() {
function test_paged_unique (line 1291) | async fn test_paged_unique() {
function test_paged_include_deleted (line 1314) | async fn test_paged_include_deleted() {
function test_search_bench_dupes (line 1361) | async fn test_search_bench_dupes() {
type QueryTokenizer (line 1397) | pub struct QueryTokenizer<'a> {
type QueryToken (line 1402) | pub enum QueryToken<'a> {
function has_uppercase (line 1412) | pub fn has_uppercase(&self) -> bool {
function is_inverse (line 1422) | pub fn is_inverse(&self) -> bool {
function new (line 1434) | pub fn new(query: &'a str) -> Self {
type Item (line 1440) | type Item = QueryToken<'a>;
method next (line 1441) | fn next(&mut self) -> Option<Self::Item> {
FILE: crates/atuin-client/src/distro.rs
function detect_linux_distribution (line 6) | pub fn detect_linux_distribution() -> String {
function detect_from_os_release (line 19) | fn detect_from_os_release() -> Option<String> {
function detect_from_debian_version (line 29) | fn detect_from_debian_version() -> Option<String> {
function detect_from_centos_release (line 35) | fn detect_from_centos_release() -> Option<String> {
function detect_from_redhat_release (line 41) | fn detect_from_redhat_release() -> Option<String> {
function detect_from_fedora_release (line 47) | fn detect_from_fedora_release() -> Option<String> {
function detect_from_arch_release (line 53) | fn detect_from_arch_release() -> Option<String> {
function detect_from_alpine_release (line 60) | fn detect_from_alpine_release() -> Option<String> {
function detect_from_suse_release (line 66) | fn detect_from_suse_release() -> Option<String> {
function detect_from_lsb_release (line 72) | fn detect_from_lsb_release() -> Option<String> {
function linux_distro_from_lsb_release (line 83) | fn linux_distro_from_lsb_release(output: &str) -> Option<String> {
FILE: crates/atuin-client/src/encryption.rs
type EncryptedHistory (line 28) | pub struct EncryptedHistory {
function generate_encoded_key (line 33) | pub fn generate_encoded_key() -> Result<(Key, String)> {
function new_key (line 40) | pub fn new_key(settings: &Settings) -> Result<Key> {
function load_key (line 57) | pub fn load_key(settings: &Settings) -> Result<Key> {
function encode_key (line 70) | pub fn encode_key(key: &Key) -> Result<String> {
function decode_key (line 83) | pub fn decode_key(key: String) -> Result<Key> {
function encrypt (line 121) | pub fn encrypt(history: &History, key: &Key) -> Result<EncryptedHistory> {
function decrypt (line 136) | pub fn decrypt(mut encrypted_history: EncryptedHistory, key: &Key) -> Re...
function format_rfc3339 (line 151) | fn format_rfc3339(ts: OffsetDateTime) -> Result<String> {
function encode (line 173) | fn encode(h: &History) -> Result<Vec<u8>> {
function decode (line 196) | fn decode(bytes: &[u8]) -> Result<History> {
function error_report (line 264) | fn error_report<E: std::fmt::Debug>(err: E) -> eyre::Report {
function test_encrypt_decrypt (line 279) | fn test_encrypt_decrypt() {
function test_decode (line 316) | fn test_decode() {
function test_decode_deleted (line 351) | fn test_decode_deleted() {
function test_decode_old (line 372) | fn test_decode_old() {
function key_encodings (line 404) | fn key_encodings() {
FILE: crates/atuin-client/src/history.rs
constant HISTORY_VERSION_V0 (line 21) | pub(crate) const HISTORY_VERSION_V0: &str = "v0";
constant HISTORY_VERSION_V1 (line 22) | pub(crate) const HISTORY_VERSION_V1: &str = "v1";
constant HISTORY_RECORD_VERSION_V0 (line 23) | const HISTORY_RECORD_VERSION_V0: u16 = 0;
constant HISTORY_RECORD_VERSION_V1 (line 24) | const HISTORY_RECORD_VERSION_V1: u16 = 1;
constant HISTORY_VERSION (line 25) | pub(crate) const HISTORY_VERSION: &str = HISTORY_VERSION_V1;
constant HISTORY_TAG (line 26) | pub const HISTORY_TAG: &str = "history";
constant HISTORY_AUTHOR_ENV (line 27) | const HISTORY_AUTHOR_ENV: &str = "ATUIN_HISTORY_AUTHOR";
constant HISTORY_INTENT_ENV (line 28) | const HISTORY_INTENT_ENV: &str = "ATUIN_HISTORY_INTENT";
type HistoryId (line 31) | pub struct HistoryId(pub String);
method from (line 40) | fn from(s: String) -> Self {
method fmt (line 34) | fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
type History (line 59) | pub struct History {
method author_from_hostname (line 107) | pub(crate) fn author_from_hostname(hostname: &str) -> String {
method normalize_optional_field (line 113) | fn normalize_optional_field(field: Option<String>) -> Option<String> {
method new (line 125) | fn new(
method serialize (line 162) | pub fn serialize(&self) -> Result<DecryptedData> {
method read_optional_string (line 197) | fn read_optional_string(bytes: &[u8]) -> Result<(Option<String>, &[u8]...
method deserialize_v0 (line 216) | fn deserialize_v0(bytes: &[u8]) -> Result<History> {
method deserialize_v1 (line 280) | fn deserialize_v1(bytes: &[u8]) -> Result<History> {
method deserialize (line 351) | pub fn deserialize(bytes: &[u8], version: &str) -> Result<History> {
method import (line 401) | pub fn import() -> builder::HistoryImportedBuilder {
method capture (line 435) | pub fn capture() -> builder::HistoryCapturedBuilder {
method daemon (line 477) | pub fn daemon() -> builder::HistoryDaemonCaptureBuilder {
method from_db (line 503) | pub fn from_db() -> builder::HistoryFromDbBuilder {
method success (line 507) | pub fn success(&self) -> bool {
method should_save (line 511) | pub fn should_save(&self, settings: &Settings) -> bool {
type HistoryStats (line 87) | pub struct HistoryStats {
function privacy_test (line 531) | fn privacy_test() {
function disable_secrets (line 589) | fn disable_secrets() {
function test_serialize_deserialize (line 606) | fn test_serialize_deserialize() {
function test_serialize_deserialize_deleted (line 634) | fn test_serialize_deserialize_deleted() {
function test_serialize_deserialize_with_author_and_intent (line 658) | fn test_serialize_deserialize_with_author_and_intent() {
function test_serialize_deserialize_version (line 681) | fn test_serialize_deserialize_version() {
FILE: crates/atuin-client/src/history/builder.rs
type HistoryImported (line 9) | pub struct HistoryImported {
method from (line 30) | fn from(imported: HistoryImported) -> Self {
type HistoryCaptured (line 52) | pub struct HistoryCaptured {
method from (line 65) | fn from(captured: HistoryCaptured) -> Self {
type HistoryFromDb (line 85) | pub struct HistoryFromDb {
method from (line 100) | fn from(from_db: HistoryFromDb) -> Self {
type HistoryDaemonCapture (line 123) | pub struct HistoryDaemonCapture {
method from (line 140) | fn from(captured: HistoryDaemonCapture) -> Self {
FILE: crates/atuin-client/src/history/store.rs
type HistoryStore (line 16) | pub struct HistoryStore {
method new (line 112) | pub fn new(store: SqliteStore, host_id: HostId, encryption_key: [u8; 3...
method push_record (line 120) | async fn push_record(&self, record: HistoryRecord) -> Result<(RecordId...
method push_batch (line 145) | async fn push_batch(&self, records: impl Iterator<Item = HistoryRecord...
method delete (line 177) | pub async fn delete(&self, id: HistoryId) -> Result<(RecordId, RecordI...
method push (line 183) | pub async fn push(&self, history: History) -> Result<(RecordId, Record...
method history (line 191) | pub async fn history(&self) -> Result<Vec<HistoryRecord>> {
method build (line 214) | pub async fn build(&self, database: &dyn Database) -> Result<()> {
method incremental_build (line 246) | pub async fn incremental_build(&self, database: &dyn Database, ids: &[...
method history_ids (line 287) | pub async fn history_ids(&self) -> Result<HashSet<HistoryId>> {
method init_store (line 298) | pub async fn init_store(&self, db: &impl Database) -> Result<()> {
type HistoryRecord (line 23) | pub enum HistoryRecord {
method serialize (line 41) | pub fn serialize(&self) -> Result<DecryptedData> {
method deserialize (line 67) | pub fn deserialize(bytes: &DecryptedData, version: &str) -> Result<Sel...
function test_serialize_deserialize_create (line 358) | fn test_serialize_deserialize_create() {
function test_serialize_deserialize_delete (line 401) | fn test_serialize_deserialize_delete() {
FILE: crates/atuin-client/src/hub.rs
type HubAuthSession (line 30) | pub struct HubAuthSession {
method start (line 60) | pub async fn start(hub_address: &str) -> Result<Self> {
method poll (line 83) | pub async fn poll(&self) -> Result<HubAuthStatus> {
method wait_for_completion (line 108) | pub async fn wait_for_completion(
type HubAuthStatus (line 41) | pub enum HubAuthStatus {
constant DEFAULT_POLL_INTERVAL (line 51) | pub const DEFAULT_POLL_INTERVAL: Duration = Duration::from_secs(2);
constant DEFAULT_AUTH_TIMEOUT (line 54) | pub const DEFAULT_AUTH_TIMEOUT: Duration = Duration::from_secs(600);
function save_session (line 138) | pub async fn save_session(token: &str) -> Result<()> {
function delete_session (line 147) | pub async fn delete_session() -> Result<()> {
function is_logged_in (line 159) | pub async fn is_logged_in() -> Result<bool> {
function get_session_token (line 167) | pub async fn get_session_token() -> Result<Option<String>> {
function link_account (line 186) | pub async fn link_account(hub_address: &str, cli_token: &str) -> Result<...
function make_url (line 223) | fn make_url(address: &str, path: &str) -> Result<String> {
function handle_resp_error (line 240) | async fn handle_resp_error(resp: reqwest::Response) -> Result<reqwest::R...
function request_code (line 266) | async fn request_code(address: &str) -> Result<CliCodeResponse> {
function verify_code (line 286) | async fn verify_code(address: &str, code: &str) -> Result<CliVerifyRespo...
FILE: crates/atuin-client/src/import/bash.rs
type Bash (line 14) | pub struct Bash {
function default_histpath (line 18) | fn default_histpath() -> Result<PathBuf> {
constant NAME (line 27) | const NAME: &'static str = "bash";
method new (line 29) | async fn new() -> Result<Self> {
method entries (line 34) | async fn entries(&mut self) -> Result<usize> {
method load (line 42) | async fn load(self, h: &mut impl Loader) -> Result<()> {
type LineType (line 96) | enum LineType<'a> {
function from (line 107) | fn from(bytes: &'a [u8]) -> Self {
function try_parse_line_as_timestamp (line 122) | fn try_parse_line_as_timestamp(line: &str) -> Option<OffsetDateTime> {
function parse_no_timestamps (line 138) | async fn parse_no_timestamps() {
function parse_with_timestamps (line 164) | async fn parse_with_timestamps() {
function parse_with_partial_timestamps (line 191) | async fn parse_with_partial_timestamps() {
function is_strictly_sorted (line 212) | fn is_strictly_sorted<T>(iter: impl IntoIterator<Item = T>) -> bool
FILE: crates/atuin-client/src/import/fish.rs
type Fish (line 16) | pub struct Fish {
function default_histpath (line 21) | fn default_histpath() -> Result<PathBuf> {
constant NAME (line 49) | const NAME: &'static str = "fish";
method new (line 51) | async fn new() -> Result<Self> {
method entries (line 56) | async fn entries(&mut self) -> Result<usize> {
method load (line 60) | async fn load(self, loader: &mut impl Loader) -> Result<()> {
function parse_complex (line 118) | async fn parse_complex() {
FILE: crates/atuin-client/src/import/mod.rs
type Importer (line 24) | pub trait Importer: Sized {
constant NAME (line 25) | const NAME: &'static str;
method new (line 26) | async fn new() -> Result<Self>;
method entries (line 27) | async fn entries(&mut self) -> Result<usize>;
method load (line 28) | async fn load(self, loader: &mut impl Loader) -> Result<()>;
type Loader (line 32) | pub trait Loader: Sync + Send {
method push (line 33) | async fn push(&mut self, hist: History) -> eyre::Result<()>;
method push (line 135) | async fn push(&mut self, hist: History) -> Result<()> {
function unix_byte_lines (line 36) | fn unix_byte_lines(input: &[u8]) -> impl Iterator<Item = &[u8]> {
type UnixByteLines (line 44) | struct UnixByteLines<'a> {
type Item (line 51) | type Item = &'a [u8];
method next (line 53) | fn next(&mut self) -> Option<Self::Item> {
method count (line 60) | fn count(self) -> usize
function count_lines (line 68) | fn count_lines(input: &[u8]) -> usize {
function get_histpath (line 72) | fn get_histpath<D>(def: D) -> Result<PathBuf>
function get_histfile_path (line 83) | fn get_histfile_path<D>(def: D) -> Result<PathBuf>
function get_histdir_path (line 90) | fn get_histdir_path<D>(def: D) -> Result<PathBuf>
function read_to_end (line 97) | fn read_to_end(path: PathBuf) -> Result<Vec<u8>> {
function is_file (line 103) | fn is_file(p: PathBuf) -> Result<PathBuf> {
function is_dir (line 113) | fn is_dir(p: PathBuf) -> Result<PathBuf> {
type TestLoader (line 129) | pub struct TestLoader {
FILE: crates/atuin-client/src/import/nu.rs
type Nu (line 16) | pub struct Nu {
function get_histpath (line 20) | fn get_histpath() -> Result<PathBuf> {
constant NAME (line 34) | const NAME: &'static str = "nu";
method new (line 36) | async fn new() -> Result<Self> {
method entries (line 41) | async fn entries(&mut self) -> Result<usize> {
method load (line 45) | async fn load(self, h: &mut impl Loader) -> Result<()> {
FILE: crates/atuin-client/src/import/nu_histdb.rs
type HistDbEntry (line 17) | pub struct HistDbEntry {
method from (line 30) | fn from(histdb_item: HistDbEntry) -> Self {
type NuHistDb (line 50) | pub struct NuHistDb {
method histpath (line 75) | pub fn histpath() -> Result<PathBuf> {
function hist_from_db (line 55) | async fn hist_from_db(dbpath: PathBuf) -> Result<Vec<HistDbEntry>> {
function hist_from_db_conn (line 60) | async fn hist_from_db_conn(pool: Pool<sqlx::Sqlite>) -> Result<Vec<HistD...
constant NAME (line 91) | const NAME: &'static str = "nu_histdb";
method new (line 95) | async fn new() -> Result<Self> {
method entries (line 103) | async fn entries(&mut self) -> Result<usize> {
method load (line 107) | async fn load(self, h: &mut impl Loader) -> Result<()> {
FILE: crates/atuin-client/src/import/powershell.rs
type PowerShell (line 12) | pub struct PowerShell {
function get_history_path (line 17) | fn get_history_path() -> Result<PathBuf> {
constant NAME (line 60) | const NAME: &'static str = "PowerShell";
method new (line 62) | async fn new() -> Result<Self> {
method entries (line 70) | async fn entries(&mut self) -> Result<usize> {
method load (line 80) | async fn load(mut self, h: &mut impl Loader) -> Result<()> {
function read_line (line 124) | fn read_line(s: &[u8]) -> Result<&str> {
constant INPUT (line 139) | const INPUT: &str = r#"cargo install atuin
constant EXPECTED (line 151) | const EXPECTED: &[&str] = &[
function test_import (line 161) | async fn test_import() {
function test_crlf (line 171) | async fn test_crlf() {
function test_timestamps (line 182) | async fn test_timestamps() {
function import (line 192) | async fn import(input: &str) -> TestLoader {
FILE: crates/atuin-client/src/import/replxx.rs
type Replxx (line 13) | pub struct Replxx {
function default_histpath (line 17) | fn default_histpath() -> Result<PathBuf> {
constant NAME (line 43) | const NAME: &'static str = "replxx";
method new (line 45) | async fn new() -> Result<Self> {
method entries (line 50) | async fn entries(&mut self) -> Result<usize> {
method load (line 54) | async fn load(self, h: &mut impl Loader) -> Result<()> {
function try_parse_line_as_timestamp (line 75) | fn try_parse_line_as_timestamp(line: &str) -> Option<OffsetDateTime> {
function parse_complex (line 95) | async fn parse_complex() {
FILE: crates/atuin-client/src/import/resh.rs
type ReshEntry (line 17) | pub struct ReshEntry {
type Resh (line 72) | pub struct Resh {
function default_histpath (line 76) | fn default_histpath() -> Result<PathBuf> {
constant NAME (line 85) | const NAME: &'static str = "resh";
method new (line 87) | async fn new() -> Result<Self> {
method entries (line 92) | async fn entries(&mut self) -> Result<usize> {
method load (line 96) | async fn load(self, h: &mut impl Loader) -> Result<()> {
FILE: crates/atuin-client/src/import/xonsh.rs
type HistoryFile (line 20) | struct HistoryFile {
type HistoryData (line 25) | struct HistoryData {
type HistoryCmd (line 31) | struct HistoryCmd {
type Xonsh (line 39) | pub struct Xonsh {
function xonsh_hist_dir (line 45) | fn xonsh_hist_dir(xonsh_data_dir: Option<String>) -> Result<PathBuf> {
function load_sessions (line 64) | fn load_sessions(hist_dir: &Path) -> Result<Vec<HistoryData>> {
function load_session (line 79) | fn load_session(path: &Path) -> Result<Option<HistoryData>> {
constant NAME (line 101) | const NAME: &'static str = "xonsh";
method new (line 103) | async fn new() -> Result<Self> {
method entries (line 112) | async fn entries(&mut self) -> Result<usize> {
method load (line 117) | async fn load(self, loader: &mut impl Loader) -> Result<()> {
function test_hist_dir_xonsh (line 165) | fn test_hist_dir_xonsh() {
function test_import (line 174) | async fn test_import() {
function expected_hist_entries (line 194) | fn expected_hist_entries() -> [History; 4] {
FILE: crates/atuin-client/src/import/xonsh_sqlite.rs
type HistDbEntry (line 18) | struct HistDbEntry {
method into_hist_with_hostname (line 28) | fn into_hist_with_hostname(self, hostname: String) -> History {
function xonsh_db_path (line 61) | fn xonsh_db_path(xonsh_data_dir: Option<String>) -> Result<PathBuf> {
type XonshSqlite (line 84) | pub struct XonshSqlite {
constant NAME (line 91) | const NAME: &'static str = "xonsh_sqlite";
method new (line 93) | async fn new() -> Result<Self> {
method entries (line 109) | async fn entries(&mut self) -> Result<usize> {
method load (line 116) | async fn load(self, loader: &mut impl Loader) -> Result<()> {
function test_db_path_xonsh (line 148) | fn test_db_path_xonsh() {
function test_import (line 157) | async fn test_import() {
function expected_hist_entries (line 177) | fn expected_hist_entries() -> [History; 4] {
FILE: crates/atuin-client/src/import/zsh.rs
type Zsh (line 17) | pub struct Zsh {
function default_histpath (line 21) | fn default_histpath() -> Result<PathBuf> {
constant NAME (line 49) | const NAME: &'static str = "zsh";
method new (line 51) | async fn new() -> Result<Self> {
method entries (line 56) | async fn entries(&mut self) -> Result<usize> {
method load (line 60) | async fn load(self, h: &mut impl Loader) -> Result<()> {
function parse_extended (line 99) | fn parse_extended(line: &str, counter: i64) -> History {
function unmetafy (line 121) | fn unmetafy(line: &[u8]) -> Option<Cow<'_, str>> {
function test_parse_extended_simple (line 150) | fn test_parse_extended_simple() {
function test_parse_file (line 189) | async fn test_parse_file() {
function test_parse_metafied (line 215) | async fn test_parse_metafied() {
FILE: crates/atuin-client/src/import/zsh_histdb.rs
type HistDbEntryCount (line 51) | pub struct HistDbEntryCount {
type HistDbEntry (line 56) | pub struct HistDbEntry {
type ZshHistDb (line 68) | pub struct ZshHistDb {
method histpath_candidate (line 96) | pub fn histpath_candidate() -> PathBuf {
method histpath (line 109) | pub fn histpath() -> Result<PathBuf> {
function hist_from_db (line 74) | async fn hist_from_db(dbpath: PathBuf) -> Result<Vec<HistDbEntry>> {
function hist_from_db_conn (line 79) | async fn hist_from_db_conn(pool: Pool<sqlx::Sqlite>) -> Result<Vec<HistD...
constant NAME (line 124) | const NAME: &'static str = "zsh_histdb";
method new (line 128) | async fn new() -> Result<Self> {
method entries (line 137) | async fn entries(&mut self) -> Result<usize> {
method load (line 141) | async fn load(self, h: &mut impl Loader) -> Result<()> {
function test_env_vars (line 182) | async fn test_env_vars() {
function test_import (line 197) | async fn test_import() {
FILE: crates/atuin-client/src/login.rs
function login (line 15) | pub async fn login(
FILE: crates/atuin-client/src/logout.rs
function logout (line 5) | pub async fn logout() -> Result<()> {
FILE: crates/atuin-client/src/meta.rs
constant LEGACY_HOST_ID_FILENAME (line 13) | const LEGACY_HOST_ID_FILENAME: &str = "host_id";
constant LEGACY_LAST_SYNC_FILENAME (line 14) | const LEGACY_LAST_SYNC_FILENAME: &str = "last_sync_time";
constant LEGACY_LAST_VERSION_CHECK_FILENAME (line 15) | const LEGACY_LAST_VERSION_CHECK_FILENAME: &str = "last_version_check_time";
constant LEGACY_LATEST_VERSION_FILENAME (line 16) | const LEGACY_LATEST_VERSION_FILENAME: &str = "latest_version";
constant LEGACY_SESSION_FILENAME (line 17) | const LEGACY_SESSION_FILENAME: &str = "session";
constant KEY_HOST_ID (line 19) | const KEY_HOST_ID: &str = "host_id";
constant KEY_LAST_SYNC (line 20) | const KEY_LAST_SYNC: &str = "last_sync_time";
constant KEY_LAST_VERSION_CHECK (line 21) | const KEY_LAST_VERSION_CHECK: &str = "last_version_check_time";
constant KEY_LATEST_VERSION (line 22) | const KEY_LATEST_VERSION: &str = "latest_version";
constant KEY_SESSION (line 23) | const KEY_SESSION: &str = "session";
constant KEY_HUB_SESSION (line 24) | const KEY_HUB_SESSION: &str = "hub_session";
constant KEY_FILES_MIGRATED (line 25) | const KEY_FILES_MIGRATED: &str = "files_migrated";
type MetaStore (line 27) | pub struct MetaStore {
method new (line 33) | pub async fn new(path: impl AsRef<Path>, timeout: f64) -> Result<Self> {
method get (line 87) | pub async fn get(&self, key: &str) -> Result<Option<String>> {
method set (line 96) | pub async fn set(&self, key: &str, value: &str) -> Result<()> {
method delete (line 109) | pub async fn delete(&self, key: &str) -> Result<()> {
method host_id (line 120) | pub async fn host_id(&self) -> Result<HostId> {
method last_sync (line 139) | pub async fn last_sync(&self) -> Result<OffsetDateTime> {
method save_sync_time (line 146) | pub async fn save_sync_time(&self) -> Result<()> {
method last_version_check (line 154) | pub async fn last_version_check(&self) -> Result<OffsetDateTime> {
method save_version_check_time (line 161) | pub async fn save_version_check_time(&self) -> Result<()> {
method latest_version (line 169) | pub async fn latest_version(&self) -> Result<Option<String>> {
method save_latest_version (line 173) | pub async fn save_latest_version(&self, version: &str) -> Result<()> {
method session_token (line 177) | pub async fn session_token(&self) -> Result<Option<String>> {
method save_session (line 181) | pub async fn save_session(&self, token: &str) -> Result<()> {
method delete_session (line 185) | pub async fn delete_session(&self) -> Result<()> {
method logged_in (line 189) | pub async fn logged_in(&self) -> Result<bool> {
method hub_session_token (line 195) | pub async fn hub_session_token(&self) -> Result<Option<String>> {
method save_hub_session (line 199) | pub async fn save_hub_session(&self, token: &str) -> Result<()> {
method delete_hub_session (line 203) | pub async fn delete_hub_session(&self) -> Result<()> {
method hub_logged_in (line 207) | pub async fn hub_logged_in(&self) -> Result<bool> {
method migrate_files (line 214) | async fn migrate_files(&self) -> Result<()> {
function new_test_store (line 300) | async fn new_test_store() -> MetaStore {
function test_get_set_delete (line 305) | async fn test_get_set_delete() {
function test_host_id_generation_and_stability (line 321) | async fn test_host_id_generation_and_stability() {
function test_sync_time (line 331) | async fn test_sync_time() {
function test_version_check_time (line 343) | async fn test_version_check_time() {
function test_session_crud (line 355) | async fn test_session_crud() {
function test_latest_version (line 373) | async fn test_latest_version() {
FILE: crates/atuin-client/src/ordering.rs
function reorder_fuzzy (line 5) | pub fn reorder_fuzzy(mode: SearchMode, query: &str, res: Vec<History>) -...
function reorder (line 12) | fn reorder<F, A>(query: &str, f: F, res: Vec<A>) -> Vec<A>
FILE: crates/atuin-client/src/plugin.rs
type OfficialPlugin (line 4) | pub struct OfficialPlugin {
method new (line 11) | pub fn new(name: &str, description: &str, install_message: &str) -> Se...
type OfficialPluginRegistry (line 20) | pub struct OfficialPluginRegistry {
method new (line 25) | pub fn new() -> Self {
method register_official_plugins (line 36) | fn register_official_plugins(&mut self) {
method get_plugin (line 50) | pub fn get_plugin(&self, name: &str) -> Option<&OfficialPlugin> {
method is_official_plugin (line 54) | pub fn is_official_plugin(&self, name: &str) -> bool {
method get_install_message (line 58) | pub fn get_install_message(&self, name: &str) -> Option<&str> {
method default (line 66) | fn default() -> Self {
function test_registry_creation (line 76) | fn test_registry_creation() {
function test_get_plugin (line 83) | fn test_get_plugin() {
function test_get_install_message (line 91) | fn test_get_install_message() {
FILE: crates/atuin-client/src/record/encryption.rs
type PASETO_V4 (line 14) | pub struct PASETO_V4;
method decrypt_cek (line 117) | fn decrypt_cek(wrapped_cek: String, key: &[u8; 32]) -> Result<Key<V4, ...
method encrypt_cek (line 141) | fn encrypt_cek(cek: Key<V4, Local>, key: &[u8; 32]) -> String {
method re_encrypt (line 55) | fn re_encrypt(
method encrypt (line 66) | fn encrypt(data: DecryptedData, ad: AdditionalData, key: &[u8; 32]) -> E...
method decrypt (line 94) | fn decrypt(data: EncryptedData, ad: AdditionalData, key: &[u8; 32]) -> R...
type AtuinPayload (line 155) | struct AtuinPayload {
type AtuinFooter (line 162) | struct AtuinFooter {
type Assertions (line 172) | struct Assertions<'a> {
function from (line 181) | fn from(ad: AdditionalData<'a>) -> Self {
function encode (line 193) | fn encode(&self) -> String {
function round_trip (line 208) | fn round_trip() {
function same_entry_different_output (line 227) | fn same_entry_different_output() {
function cannot_decrypt_different_key (line 250) | fn cannot_decrypt_different_key() {
function cannot_decrypt_different_id (line 269) | fn cannot_decrypt_different_id() {
function re_encrypt_round_trip (line 292) | fn re_encrypt_round_trip() {
function full_record_round_trip (line 324) | fn full_record_round_trip() {
function full_record_round_trip_fail (line 347) | fn full_record_round_trip_fail() {
FILE: crates/atuin-client/src/record/sqlite_store.rs
type SqliteStore (line 27) | pub struct SqliteStore {
method new (line 32) | pub async fn new(path: impl AsRef<Path>, timeout: f64) -> Result<Self> {
method setup_db (line 65) | async fn setup_db(pool: &SqlitePool) -> Result<()> {
method save_raw (line 73) | async fn save_raw(
method query_row (line 96) | fn query_row(row: SqliteRow) -> Record<EncryptedData> {
method load_all (line 118) | async fn load_all(&self) -> Result<Vec<Record<EncryptedData>>> {
method push_batch (line 130) | async fn push_batch(
method get (line 145) | async fn get(&self, id: RecordId) -> Result<Record<EncryptedData>> {
method delete (line 155) | async fn delete(&self, id: RecordId) -> Result<()> {
method delete_all (line 164) | async fn delete_all(&self) -> Result<()> {
method last (line 170) | async fn last(&self, host: HostId, tag: &str) -> Result<Option<Record<En...
method first (line 186) | async fn first(&self, host: HostId, tag: &str) -> Result<Option<Record<E...
method len_all (line 190) | async fn len_all(&self) -> Result<u64> {
method len_tag (line 200) | async fn len_tag(&self, tag: &str) -> Result<u64> {
method len (line 212) | async fn len(&self, host: HostId, tag: &str) -> Result<u64> {
method next (line 222) | async fn next(
method idx (line 243) | async fn idx(
method status (line 264) | async fn status(&self) -> Result<RecordStatus> {
method all_tagged (line 288) | async fn all_tagged(&self, tag: &str) -> Result<Vec<Record<EncryptedData...
method re_encrypt (line 300) | async fn re_encrypt(&self, old_key: &[u8; 32], new_key: &[u8; 32]) -> Re...
method verify (line 339) | async fn verify(&self, key: &[u8; 32]) -> Result<()> {
method purge (line 351) | async fn purge(&self, key: &[u8; 32]) -> Result<()> {
function test_record (line 387) | fn test_record() -> Record<EncryptedData> {
function create_db (line 401) | async fn create_db() {
function push_record (line 412) | async fn push_record() {
function get_record (line 422) | async fn get_record() {
function last (line 435) | async fn last() {
function first (line 455) | async fn first() {
function len (line 475) | async fn len() {
function len_tag (line 491) | async fn len_tag() {
function len_different_tags (line 507) | async fn len_different_tags() {
function append_a_bunch (line 529) | async fn append_a_bunch() {
function append_a_big_bunch (line 556) | async fn append_a_big_bunch() {
function re_encrypt (line 581) | async fn re_encrypt() {
FILE: crates/atuin-client/src/record/store.rs
type Store (line 11) | pub trait Store {
method push (line 13) | async fn push(&self, record: &Record<EncryptedData>) -> Result<()> {
method push_batch (line 18) | async fn push_batch(
method get (line 23) | async fn get(&self, id: RecordId) -> Result<Record<EncryptedData>>;
method delete (line 25) | async fn delete(&self, id: RecordId) -> Result<()>;
method delete_all (line 26) | async fn delete_all(&self) -> Result<()>;
method len_all (line 28) | async fn len_all(&self) -> Result<u64>;
method len (line 29) | async fn len(&self, host: HostId, tag: &str) -> Result<u64>;
method len_tag (line 30) | async fn len_tag(&self, tag: &str) -> Result<u64>;
method last (line 32) | async fn last(&self, host: HostId, tag: &str) -> Result<Option<Record<...
method first (line 33) | async fn first(&self, host: HostId, tag: &str) -> Result<Option<Record...
method re_encrypt (line 35) | async fn re_encrypt(&self, old_key: &[u8; 32], new_key: &[u8; 32]) -> ...
method verify (line 36) | async fn verify(&self, key: &[u8; 32]) -> Result<()>;
method purge (line 37) | async fn purge(&self, key: &[u8; 32]) -> Result<()>;
method next (line 40) | async fn next(
method idx (line 49) | async fn idx(
method status (line 56) | async fn status(&self) -> Result<RecordStatus>;
method all_tagged (line 59) | async fn all_tagged(&self, tag: &str) -> Result<Vec<Record<EncryptedDa...
FILE: crates/atuin-client/src/record/sync.rs
type SyncError (line 14) | pub enum SyncError {
type Operation (line 32) | pub enum Operation {
function diff (line 52) | pub async fn diff(
function operations (line 86) | pub async fn operations(
function sync_upload (line 159) | async fn sync_upload(
function sync_download (line 218) | async fn sync_download(
function sync_remote (line 275) | pub async fn sync_remote(
function sync (line 327) | pub async fn sync(
function test_record (line 353) | fn test_record() -> Record<EncryptedData> {
function build_test_diff (line 371) | async fn build_test_diff(
function test_basic_diff (line 399) | async fn test_basic_diff() {
function build_two_way_diff (line 423) | async fn build_two_way_diff() {
function build_complex_diff (line 466) | async fn build_complex_diff() {
FILE: crates/atuin-client/src/register.rs
function register_classic (line 5) | pub async fn register_classic(
FILE: crates/atuin-client/src/secrets.rs
type TestValue (line 6) | pub enum TestValue<'a> {
function test_secrets (line 147) | fn test_secrets() {
FILE: crates/atuin-client/src/settings.rs
constant HISTORY_PAGE_SIZE (line 19) | pub const HISTORY_PAGE_SIZE: i64 = 100;
type HubEndpoint (line 32) | pub struct HubEndpoint(String);
method as_ref (line 47) | fn as_ref(&self) -> &str {
constant DEFAULT_SYNC_ADDRESS (line 35) | pub const DEFAULT_SYNC_ADDRESS: &str = "https://api.atuin.sh";
constant DEFAULT_HUB_ENDPOINT (line 38) | pub const DEFAULT_HUB_ENDPOINT: &str = "https://hub.atuin.sh";
method default (line 41) | fn default() -> Self {
type SearchMode (line 53) | pub enum SearchMode {
method as_str (line 73) | pub fn as_str(&self) -> &'static str {
method next (line 82) | pub fn next(&self, settings: &Settings) -> Self {
type FilterMode (line 99) | pub enum FilterMode {
method as_str (line 120) | pub fn as_str(&self) -> &'static str {
type ExitMode (line 133) | pub enum ExitMode {
type Dialect (line 144) | pub enum Dialect {
function from (line 153) | fn from(d: Dialect) -> interim::Dialect {
type Timezone (line 168) | pub struct Timezone(pub UtcOffset);
method fmt (line 170) | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
type Err (line 179) | type Err = Error;
method from_str (line 181) | fn from_str(s: &str) -> Result<Self> {
type Style (line 212) | pub enum Style {
type WordJumpMode (line 224) | pub enum WordJumpMode {
type KeymapMode (line 233) | pub enum KeymapMode {
method as_str (line 248) | pub fn as_str(&self) -> &'static str {
type CursorStyle (line 264) | pub enum CursorStyle {
method as_str (line 288) | pub fn as_str(&self) -> &'static str {
type Stats (line 302) | pub struct Stats {
method common_prefix_default (line 312) | fn common_prefix_default() -> Vec<String> {
method common_subcommands_default (line 316) | fn common_subcommands_default() -> Vec<String> {
method ignored_commands_default (line 345) | fn ignored_commands_default() -> Vec<String> {
method default (line 351) | fn default() -> Self {
type Sync (line 361) | pub struct Sync {
type SyncProtocol (line 376) | pub enum SyncProtocol {
type Keys (line 387) | pub struct Keys {
method standard_defaults (line 399) | pub fn standard_defaults() -> Self {
method has_non_default_values (line 411) | pub fn has_non_default_values(&self) -> bool {
type KeyRuleConfig (line 424) | pub struct KeyRuleConfig {
type KeyBindingConfig (line 436) | pub enum KeyBindingConfig {
type KeymapConfig (line 446) | pub struct KeymapConfig {
method is_empty (line 461) | pub fn is_empty(&self) -> bool {
type Preview (line 471) | pub struct Preview {
type Theme (line 476) | pub struct Theme {
type Daemon (line 488) | pub struct Daemon {
type Search (line 514) | pub struct Search {
type Tmux (line 532) | pub struct Tmux {
type LogLevel (line 546) | pub enum LogLevel {
method as_directive (line 557) | pub fn as_directive(&self) -> &'static str {
type LogConfig (line 570) | pub struct LogConfig {
type Logs (line 585) | pub struct Logs {
method default_enabled (line 688) | fn default_enabled() -> bool {
method default_retention (line 692) | fn default_retention() -> u64 {
method search_enabled (line 698) | pub fn search_enabled(&self) -> bool {
method daemon_enabled (line 704) | pub fn daemon_enabled(&self) -> bool {
method ai_enabled (line 710) | pub fn ai_enabled(&self) -> bool {
method search_level (line 716) | pub fn search_level(&self) -> LogLevel {
method daemon_level (line 722) | pub fn daemon_level(&self) -> LogLevel {
method ai_level (line 728) | pub fn ai_level(&self) -> LogLevel {
method search_retention (line 734) | pub fn search_retention(&self) -> u64 {
method daemon_retention (line 740) | pub fn daemon_retention(&self) -> u64 {
method ai_retention (line 746) | pub fn ai_retention(&self) -> u64 {
method search_path (line 751) | pub fn search_path(&self) -> PathBuf {
method daemon_path (line 757) | pub fn daemon_path(&self) -> PathBuf {
method ai_path (line 763) | pub fn ai_path(&self) -> PathBuf {
type Ai (line 616) | pub struct Ai {
method default (line 633) | fn default() -> Self {
method default (line 641) | fn default() -> Self {
method default (line 651) | fn default() -> Self {
method default (line 665) | fn default() -> Self {
method default (line 770) | fn default() -> Self {
method default (line 789) | fn default() -> Self {
type PreviewStrategy (line 800) | pub enum PreviewStrategy {
type UiColumnType (line 817) | pub enum UiColumnType {
method default_width (line 839) | pub fn default_width(&self) -> u16 {
type UiColumn (line 862) | pub struct UiColumn {
method new (line 870) | pub fn new(column_type: UiColumnType) -> Self {
method with_width (line 878) | pub fn with_width(column_type: UiColumnType, width: u16) -> Self {
method deserialize (line 890) | fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
type Ui (line 958) | pub struct Ui {
method default_columns (line 968) | fn default_columns() -> Vec<UiColumn> {
method validate (line 978) | pub fn validate(&self) -> Result<()> {
method default (line 991) | fn default() -> Self {
type Settings (line 999) | pub struct Settings {
method utc (line 1112) | pub fn utc() -> Self {
method effective_data_dir (line 1123) | pub(crate) fn effective_data_dir() -> PathBuf {
method meta_store (line 1132) | pub async fn meta_store() -> Result<&'static crate::meta::MetaStore> {
method host_id (line 1143) | pub async fn host_id() -> Result<HostId> {
method last_sync (line 1147) | pub async fn last_sync() -> Result<OffsetDateTime> {
method save_sync_time (line 1151) | pub async fn save_sync_time() -> Result<()> {
method last_version_check (line 1155) | pub async fn last_version_check() -> Result<OffsetDateTime> {
method save_version_check_time (line 1159) | pub async fn save_version_check_time() -> Result<()> {
method should_sync (line 1163) | pub async fn should_sync(&self) -> Result<bool> {
method logged_in (line 1181) | pub async fn logged_in(&self) -> Result<bool> {
method session_token (line 1185) | pub async fn session_token(&self) -> Result<String> {
method hub_session_token (line 1192) | pub async fn hub_session_token(&self) -> Result<String> {
method normalize_url (line 1200) | fn normalize_url(url: &str) -> &str {
method is_official_address (line 1205) | fn is_official_address(url: &str) -> bool {
method is_hub_sync (line 1217) | pub fn is_hub_sync(&self) -> bool {
method active_hub_endpoint (line 1230) | pub fn active_hub_endpoint(&self) -> Option<HubEndpoint> {
method sync_auth_token (line 1254) | pub async fn sync_auth_token(&self) -> Result<crate::api_client::AuthT...
method needs_update_check (line 1277) | async fn needs_update_check(&self) -> Result<bool> {
method latest_version (line 1286) | async fn latest_version(&self) -> Result<Version> {
method needs_update (line 1317) | pub async fn needs_update(&self) -> Option<Version> {
method default_filter_mode (line 1340) | pub fn default_filter_mode(&self, git_root: bool) -> FilterMode {
method needs_update (line 1358) | pub async fn needs_update(&self) -> Option<Version> {
method builder (line 1362) | pub fn builder() -> Result<ConfigBuilder<DefaultState>> {
method builder_with_data_dir (line 1366) | fn builder_with_data_dir(data_dir: &std::path::Path) -> Result<ConfigB...
method get_config_path (line 1485) | pub fn get_config_path() -> Result<PathBuf> {
method new (line 1504) | pub fn new() -> Result<Self> {
method expand_path (line 1590) | fn expand_path(path: String) -> Result<String> {
method example_config (line 1596) | pub fn example_config() -> &'static str {
method paths_ok (line 1600) | pub fn paths_ok(&self) -> bool {
method default (line 1612) | fn default() -> Self {
function init_meta_config_for_testing (line 1634) | pub fn init_meta_config_for_testing(meta_db_path: impl Into<String>, loc...
function test_local_timeout (line 1639) | pub(crate) fn test_local_timeout() -> f64 {
function can_parse_offset_timezone_spec (line 1657) | fn can_parse_offset_timezone_spec() -> Result<()> {
function can_choose_workspace_filters_when_in_git_context (line 1687) | fn can_choose_workspace_filters_when_in_git_context() -> Result<()> {
function wont_choose_workspace_filters_when_not_in_git_context (line 1707) | fn wont_choose_workspace_filters_when_not_in_git_context() -> Result<()> {
function wont_choose_workspace_filters_when_workspaces_disabled (line 1724) | fn wont_choose_workspace_filters_when_workspaces_disabled() -> Result<()> {
function builder_with_data_dir_uses_custom_paths (line 1741) | fn builder_with_data_dir_uses_custom_paths() -> Result<()> {
function effective_data_dir_returns_default_when_not_set (line 1787) | fn effective_data_dir_returns_default_when_not_set() {
function keymap_config_deserializes_simple_binding (line 1796) | fn keymap_config_deserializes_simple_binding() {
function keymap_config_deserializes_conditional_binding (line 1807) | fn keymap_config_deserializes_conditional_binding() {
function keymap_config_deserializes_vim_normal (line 1830) | fn keymap_config_deserializes_vim_normal() {
function keymap_config_is_empty_when_default (line 1838) | fn keymap_config_is_empty_when_default() {
function keymap_config_mixed_modes (line 1844) | fn keymap_config_mixed_modes() {
FILE: crates/atuin-client/src/settings/dotfiles.rs
type Settings (line 4) | pub struct Settings {
FILE: crates/atuin-client/src/settings/kv.rs
type Settings (line 4) | pub struct Settings {
method default (line 9) | fn default() -> Self {
FILE: crates/atuin-client/src/settings/meta.rs
type Settings (line 4) | pub struct Settings {
method default (line 9) | fn default() -> Self {
FILE: crates/atuin-client/src/settings/scripts.rs
type Settings (line 4) | pub struct Settings {
method default (line 9) | fn default() -> Self {
FILE: crates/atuin-client/src/settings/watcher.rs
function global_settings_watcher (line 47) | pub fn global_settings_watcher() -> Result<&'static SettingsWatcher> {
type SettingsWatcher (line 60) | pub struct SettingsWatcher {
method new (line 72) | pub fn new() -> Result<Self> {
method subscribe (line 92) | pub fn subscribe(&self) -> watch::Receiver<Arc<Settings>> {
method current (line 97) | pub fn current(&self) -> Arc<Settings> {
method config_path (line 102) | fn config_path() -> PathBuf {
method create_watcher (line 112) | fn create_watcher(
method debounce_loop (line 208) | fn debounce_loop(
FILE: crates/atuin-client/src/sync.rs
function hash_str (line 17) | pub fn hash_str(string: &str) -> String {
function sync_download (line 35) | async fn sync_download(
function sync_upload (line 129) | async fn sync_upload(
function sync (line 194) | pub async fn sync(settings: &Settings, force: bool, db: &impl Database) ...
FILE: crates/atuin-client/src/theme.rs
type Meaning (line 24) | pub enum Meaning {
type ThemeConfig (line 37) | pub struct ThemeConfig {
type ThemeDefinitionConfigBlock (line 46) | pub struct ThemeDefinitionConfigBlock {
type Theme (line 58) | pub struct Theme {
method get_base (line 69) | pub fn get_base(&self) -> ContentStyle {
method get_info (line 73) | pub fn get_info(&self) -> ContentStyle {
method get_warning (line 77) | pub fn get_warning(&self) -> ContentStyle {
method get_error (line 81) | pub fn get_error(&self) -> ContentStyle {
method get_alert (line 87) | pub fn get_alert(&self, severity: log::Level) -> ContentStyle {
method new (line 91) | pub fn new(
method closest_meaning (line 103) | pub fn closest_meaning<'a>(&self, meaning: &'a Meaning) -> &'a Meaning {
method as_style (line 114) | pub fn as_style(&self, meaning: Meaning) -> ContentStyle {
method from_foreground_colors (line 123) | pub fn from_foreground_colors(
method from_map (line 148) | fn from_map(
function from_string (line 168) | fn from_string(name: &str) -> Result<Color, String> {
type StyleFactory (line 209) | pub struct StyleFactory {}
method from_fg_string (line 212) | fn from_fg_string(name: &str) -> Result<ContentStyle, String> {
method known_fg_string (line 221) | fn known_fg_string(name: &str) -> ContentStyle {
method from_fg_color (line 225) | fn from_fg_color(color: Color) -> ContentStyle {
method from_fg_color_and_attributes (line 232) | fn from_fg_color_and_attributes(color: Color, attributes: Attributes) ...
type ThemeManager (line 363) | pub struct ThemeManager {
method new (line 371) | pub fn new(debug: Option<bool>, theme_dir: Option<String>) -> Self {
method load_theme_from_file (line 384) | pub fn load_theme_from_file(
method load_theme_from_config (line 424) | pub fn load_theme_from_config(
method load_theme (line 478) | pub fn load_theme(&mut self, name: &str, max_depth: Option<u8>) -> &Th...
function test_can_load_builtin_theme (line 501) | fn test_can_load_builtin_theme() {
function test_can_create_theme (line 511) | fn test_can_create_theme() {
function test_can_fallback_when_meaning_missing (line 530) | fn test_can_fallback_when_meaning_missing() {
function test_no_fallbacks_are_circular (line 604) | fn test_no_fallbacks_are_circular() {
function test_can_get_colors_via_convenience_functions (line 612) | fn test_can_get_colors_via_convenience_functions() {
function test_can_use_parent_theme_for_fallbacks (line 629) | fn test_can_use_parent_theme_for_fallbacks() {
function test_can_debug_theme (line 735) | fn test_can_debug_theme() {
function test_can_parse_color_strings_correctly (line 777) | fn test_can_parse_color_strings_correctly() {
FILE: crates/atuin-client/src/utils.rs
function get_hostname (line 1) | pub(crate) fn get_hostname() -> String {
function get_username (line 6) | pub(crate) fn get_username() -> String {
function get_host_user (line 12) | pub(crate) fn get_host_user() -> String {
FILE: crates/atuin-common/src/api.rs
type UserResponse (line 15) | pub struct UserResponse {
type RegisterRequest (line 20) | pub struct RegisterRequest {
type RegisterResponse (line 27) | pub struct RegisterResponse {
type DeleteUserResponse (line 32) | pub struct DeleteUserResponse {}
type ChangePasswordRequest (line 35) | pub struct ChangePasswordRequest {
type ChangePasswordResponse (line 41) | pub struct ChangePasswordResponse {}
type LoginRequest (line 44) | pub struct LoginRequest {
type LoginResponse (line 50) | pub struct LoginResponse {
type AddHistoryRequest (line 55) | pub struct AddHistoryRequest {
type CountResponse (line 64) | pub struct CountResponse {
type SyncHistoryRequest (line 69) | pub struct SyncHistoryRequest {
type SyncHistoryResponse (line 78) | pub struct SyncHistoryResponse {
type ErrorResponse (line 83) | pub struct ErrorResponse<'a> {
type IndexResponse (line 88) | pub struct IndexResponse {
type StatusResponse (line 94) | pub struct StatusResponse {
type DeleteHistoryRequest (line 107) | pub struct DeleteHistoryRequest {
type MessageResponse (line 112) | pub struct MessageResponse {
type MeResponse (line 117) | pub struct MeResponse {
type CliCodeResponse (line 125) | pub struct CliCodeResponse {
type CliVerifyResponse (line 131) | pub struct CliVerifyResponse {
FILE: crates/atuin-common/src/calendar.rs
type TimePeriod (line 4) | pub enum TimePeriod {
type TimePeriodInfo (line 11) | pub struct TimePeriodInfo {
FILE: crates/atuin-common/src/record.rs
type DecryptedData (line 9) | pub struct DecryptedData(pub Vec<u8>);
type EncryptedData (line 12) | pub struct EncryptedData {
type Diff (line 18) | pub struct Diff {
type Host (line 26) | pub struct Host {
method new (line 32) | pub fn new(id: HostId) -> Self {
type RecordIdx (line 43) | pub type RecordIdx = u64;
type Record (line 47) | pub struct Record<Data> {
type AdditionalData (line 78) | pub struct AdditionalData<'a> {
function append (line 87) | pub fn append(&self, data: Vec<u8>) -> Record<DecryptedData> {
type RecordStatus (line 101) | pub struct RecordStatus {
method extend (line 113) | fn extend<T: IntoIterator<Item = (HostId, String, RecordIdx)>>(&mut se...
method new (line 121) | pub fn new() -> RecordStatus {
method set (line 128) | pub fn set(&mut self, tail: Record<DecryptedData>) {
method set_raw (line 132) | pub fn set_raw(&mut self, host: HostId, tag: String, tail_id: RecordId...
method get (line 136) | pub fn get(&self, host: HostId, tag: String) -> Option<RecordIdx> {
method diff (line 147) | pub fn diff(&self, other: &Self) -> Vec<Diff> {
method default (line 107) | fn default() -> Self {
type Encryption (line 202) | pub trait Encryption {
method re_encrypt (line 203) | fn re_encrypt(
method encrypt (line 212) | fn encrypt(data: DecryptedData, ad: AdditionalData, key: &[u8; 32]) ->...
method decrypt (line 213) | fn decrypt(data: EncryptedData, ad: AdditionalData, key: &[u8; 32]) ->...
function encrypt (line 217) | pub fn encrypt<E: Encryption>(self, key: &[u8; 32]) -> Record<EncryptedD...
function decrypt (line 238) | pub fn decrypt<E: Encryption>(self, key: &[u8; 32]) -> Result<Record<Dec...
function re_encrypt (line 257) | pub fn re_encrypt<E: Encryption>(
function test_record (line 288) | fn test_record() -> Record<DecryptedData> {
function record_index (line 299) | fn record_index() {
function record_index_overwrite (line 315) | fn record_index_overwrite() {
function record_index_no_diff (line 333) | fn record_index_no_diff() {
function record_index_single_diff (line 350) | fn record_index_single_diff() {
function record_index_multi_diff (line 377) | fn record_index_multi_diff() {
FILE: crates/atuin-common/src/shell.rs
type Shell (line 8) | pub enum Shell {
method fmt (line 21) | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
method current (line 48) | pub fn current() -> Shell {
method from_env (line 65) | pub fn from_env() -> Shell {
method config_file (line 71) | pub fn config_file(&self) -> Option<std::path::PathBuf> {
method default_shell (line 93) | pub fn default_shell() -> Result<Shell, ShellError> {
method from_string (line 121) | pub fn from_string(name: String) -> Shell {
method is_posixish (line 138) | pub fn is_posixish(&self) -> bool {
method run_interactive (line 142) | pub fn run_interactive<I, S>(&self, args: I) -> Result<String, ShellEr...
type ShellError (line 39) | pub enum ShellError {
function shell_name (line 165) | pub fn shell_name(parent: Option<&Process>) -> String {
FILE: crates/atuin-common/src/tls.rs
function ensure_crypto_provider (line 9) | pub fn ensure_crypto_provider() {
FILE: crates/atuin-common/src/utils.rs
function crypto_random_bytes (line 12) | pub fn crypto_random_bytes<const N: usize>() -> [u8; N] {
function crypto_random_string (line 23) | pub fn crypto_random_string<const N: usize>() -> String {
function uuid_v7 (line 31) | pub fn uuid_v7() -> Uuid {
function uuid_v4 (line 35) | pub fn uuid_v4() -> String {
function has_git_dir (line 39) | pub fn has_git_dir(path: &str) -> bool {
function in_git_repo (line 49) | pub fn in_git_repo(path: &str) -> Option<PathBuf> {
function home_dir (line 68) | pub fn home_dir() -> PathBuf {
function config_dir (line 74) | pub fn config_dir() -> PathBuf {
function data_dir (line 80) | pub fn data_dir() -> PathBuf {
function runtime_dir (line 87) | pub fn runtime_dir() -> PathBuf {
function logs_dir (line 91) | pub fn logs_dir() -> PathBuf {
function dotfiles_cache_dir (line 95) | pub fn dotfiles_cache_dir() -> PathBuf {
function get_current_dir (line 103) | pub fn get_current_dir() -> String {
function broken_symlink (line 114) | pub fn broken_symlink<P: Into<PathBuf>>(path: P) -> bool {
type Escapable (line 125) | pub trait Escapable: AsRef<str> {
method escape_control (line 126) | fn escape_control(&self) -> Cow<'_, str> {
function unquote (line 149) | pub fn unquote(s: &str) -> Result<String> {
function test_dirs (line 186) | fn test_dirs() {
function test_config_dir_xdg (line 195) | fn test_config_dir_xdg() {
function test_config_dir (line 209) | fn test_config_dir() {
function test_data_dir_xdg (line 222) | fn test_data_dir_xdg() {
function test_data_dir (line 233) | fn test_data_dir() {
function uuid_is_unique (line 244) | fn uuid_is_unique() {
function escape_control_characters (line 260) | fn escape_control_characters() {
function escape_no_control_characters (line 277) | fn escape_no_control_characters() {
function dumb_random_test (line 290) | fn dumb_random_test() {
FILE: crates/atuin-daemon/build.rs
function main (line 5) | fn main() -> std::io::Result<()> {
FILE: crates/atuin-daemon/src/client.rs
type HistoryClient (line 33) | pub struct HistoryClient {
method new (line 67) | pub async fn new(path: String) -> Result<Self> {
method new (line 93) | pub async fn new(port: u64) -> Result<Self> {
method start_history (line 114) | pub async fn start_history(&mut self, h: History) -> Result<StartHisto...
method end_history (line 128) | pub async fn end_history(
method status (line 139) | pub async fn status(&mut self) -> Result<StatusReply> {
method shutdown (line 143) | pub async fn shutdown(&mut self) -> Result<bool> {
type DaemonClientErrorKind (line 38) | pub enum DaemonClientErrorKind {
function classify_error (line 46) | pub fn classify_error(error: &eyre::Report) -> DaemonClientErrorKind {
type SearchClient (line 149) | pub struct SearchClient {
method new (line 155) | pub async fn new(path: String) -> Result<Self> {
method new (line 179) | pub async fn new(port: u64) -> Result<Self> {
method search (line 201) | pub async fn search(
method from (line 224) | fn from(filter_mode: FilterMode) -> Self {
method from (line 237) | fn from(context: Context) -> Self {
type ControlClient (line 257) | pub struct ControlClient {
method new (line 264) | pub async fn new(path: String) -> Result<Self> {
method new (line 289) | pub async fn new(port: u64) -> Result<Self> {
method from_settings (line 312) | pub async fn from_settings(settings: &Settings) -> Result<Self> {
method from_settings (line 318) | pub async fn from_settings(settings: &Settings) -> Result<Self> {
method send_event (line 323) | pub async fn send_event(&mut self, event: DaemonEvent) -> Result<()> {
function daemon_event_to_proto (line 334) | fn daemon_event_to_proto(event: DaemonEvent) -> crate::control::send_eve...
function emit_event (line 381) | pub async fn emit_event(event: DaemonEvent) -> Result<()> {
function emit_event_with_settings (line 389) | pub async fn emit_event_with_settings(
FILE: crates/atuin-daemon/src/components/history.rs
constant DAEMON_PROTOCOL_VERSION (line 28) | const DAEMON_PROTOCOL_VERSION: u32 = 1;
type HistoryComponent (line 37) | pub struct HistoryComponent {
method new (line 54) | pub fn new() -> Self {
method grpc_service (line 67) | pub fn grpc_service(&self) -> HistoryServer<HistoryGrpcService> {
type HistoryComponentInner (line 41) | struct HistoryComponentInner {
method default (line 75) | fn default() -> Self {
method name (line 82) | fn name(&self) -> &'static str {
method start (line 86) | async fn start(&mut self, handle: DaemonHandle) -> Result<()> {
method handle_event (line 99) | async fn handle_event(&mut self, _event: &DaemonEvent) -> Result<()> {
method stop (line 104) | async fn stop(&mut self) -> Result<()> {
type HistoryGrpcService (line 113) | pub struct HistoryGrpcService {
method start_history (line 120) | async fn start_history(
method end_history (line 161) | async fn end_history(
method status (line 227) | async fn status(
method shutdown (line 242) | async fn shutdown(
FILE: crates/atuin-daemon/src/components/search.rs
constant PAGE_SIZE (line 25) | const PAGE_SIZE: usize = 5000;
constant RESULTS_LIMIT (line 26) | const RESULTS_LIMIT: u32 = 200;
constant FRECENCY_REFRESH_INTERVAL_SECS (line 28) | const FRECENCY_REFRESH_INTERVAL_SECS: u64 = 60;
type SearchComponent (line 37) | pub struct SearchComponent {
method new (line 46) | pub fn new() -> Self {
method grpc_service (line 56) | pub fn grpc_service(&self) -> SearchServer<SearchGrpcService> {
method rebuild_index (line 63) | async fn rebuild_index(&self) -> Result<()> {
method default (line 106) | fn default() -> Self {
method name (line 113) | fn name(&self) -> &'static str {
method start (line 117) | async fn start(&mut self, handle: DaemonHandle) -> Result<()> {
method handle_event (line 182) | async fn handle_event(&mut self, event: &DaemonEvent) -> Result<()> {
method stop (line 263) | async fn stop(&mut self) -> Result<()> {
type SearchGrpcService (line 276) | pub struct SearchGrpcService {
type SearchStream (line 282) | type SearchStream = Pin<Box<dyn Stream<Item = Result<SearchResponse, Sta...
method search (line 285) | async fn search(
function convert_filter_mode (line 369) | fn convert_filter_mode(
function with_trailing_slash (line 398) | pub fn with_trailing_slash(s: &str) -> String {
function with_trailing_slash (line 407) | pub fn with_trailing_slash(s: &str) -> String {
FILE: crates/atuin-daemon/src/components/sync.rs
type SyncCommand (line 21) | enum SyncCommand {
type SyncState (line 30) | enum SyncState {
type SyncComponent (line 45) | pub struct SyncComponent {
method new (line 52) | pub fn new() -> Self {
method default (line 61) | fn default() -> Self {
method name (line 68) | fn name(&self) -> &'static str {
method start (line 72) | async fn start(&mut self, handle: DaemonHandle) -> Result<()> {
method handle_event (line 83) | async fn handle_event(&mut self, event: &DaemonEvent) -> Result<()> {
method stop (line 93) | async fn stop(&mut self) -> Result<()> {
function sync_loop (line 110) | async fn sync_loop(handle: DaemonHandle, mut cmd_rx: mpsc::Receiver<Sync...
function do_sync_tick (line 190) | async fn do_sync_tick(
FILE: crates/atuin-daemon/src/control/service.rs
type ControlService (line 21) | pub struct ControlService {
method new (line 27) | pub fn new(handle: DaemonHandle) -> Self {
method into_server (line 32) | pub fn into_server(self) -> ControlServer<Self> {
method send_event (line 40) | async fn send_event(
function proto_event_to_daemon_event (line 60) | fn proto_event_to_daemon_event(event: Event) -> Result<DaemonEvent, Stat...
FILE: crates/atuin-daemon/src/daemon.rs
type DaemonState (line 30) | pub struct DaemonState {
type DaemonHandle (line 75) | pub struct DaemonHandle {
method emit (line 86) | pub fn emit(&self, event: DaemonEvent) {
method subscribe (line 97) | pub fn subscribe(&self) -> broadcast::Receiver<DaemonEvent> {
method shutdown (line 102) | pub fn shutdown(&self) {
method settings (line 112) | pub async fn settings(&self) -> tokio::sync::RwLockReadGuard<'_, Setti...
method reload_settings (line 120) | pub async fn reload_settings(&self) -> Result<()> {
method apply_settings (line 130) | pub async fn apply_settings(&self, settings: Settings) {
method encryption_key (line 137) | pub fn encryption_key(&self) -> &[u8; 32] {
method history_db (line 144) | pub fn history_db(&self) -> &HistoryDatabase {
method store (line 149) | pub fn store(&self) -> &SqliteStore {
method fmt (line 155) | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
type Component (line 216) | pub trait Component: Send + Sync {
method name (line 218) | fn name(&self) -> &'static str;
method start (line 225) | async fn start(&mut self, handle: DaemonHandle) -> Result<()>;
method handle_event (line 232) | async fn handle_event(&mut self, event: &DaemonEvent) -> Result<()>;
method stop (line 237) | async fn stop(&mut self) -> Result<()>;
type Daemon (line 260) | pub struct Daemon {
method builder (line 267) | pub fn builder(settings: Settings) -> DaemonBuilder {
method handle (line 274) | pub fn handle(&self) -> DaemonHandle {
method start_components (line 282) | pub async fn start_components(&mut self) -> Result<()> {
method run_event_loop (line 297) | pub async fn run_event_loop(&mut self) -> Result<()> {
method stop_components (line 327) | pub async fn stop_components(&mut self) {
method run (line 345) | pub async fn run(mut self) -> Result<()> {
method dispatch_event (line 353) | async fn dispatch_event(&mut self, event: &DaemonEvent) {
type DaemonBuilder (line 386) | pub struct DaemonBuilder {
method new (line 395) | pub fn new(settings: Settings) -> Self {
method store (line 405) | pub fn store(mut self, store: SqliteStore) -> Self {
method history_db (line 411) | pub fn history_db(mut self, db: HistoryDatabase) -> Self {
method component (line 419) | pub fn component(mut self, component: impl Component + 'static) -> Self {
method build (line 427) | pub async fn build(self) -> Result<Daemon> {
FILE: crates/atuin-daemon/src/events.rs
type DaemonEvent (line 18) | pub enum DaemonEvent {
FILE: crates/atuin-daemon/src/lib.rs
function boot (line 29) | pub async fn boot(
function shutdown_signal (line 113) | async fn shutdown_signal() {
function shutdown_signal (line 127) | async fn shutdown_signal() {
FILE: crates/atuin-daemon/src/search/index.rs
function parse_uuid_bytes (line 29) | fn parse_uuid_bytes(s: &str) -> Option<[u8; 16]> {
function format_uuid_bytes (line 34) | fn format_uuid_bytes(bytes: &[u8; 16]) -> String {
type FrecencyData (line 40) | pub struct FrecencyData {
method record_use (line 49) | pub fn record_use(&mut self, timestamp: i64) {
method compute (line 68) | pub fn compute(&self, now: i64, recency_mul: f64, frequency_mul: f64) ...
type CommandData (line 101) | pub struct CommandData {
method new (line 122) | pub fn new(history: &History, interner: &ThreadedRodeo) -> Option<Self> {
method add_invocation (line 154) | pub fn add_invocation(&mut self, history: &History, interner: &Threade...
method most_recent_id (line 183) | pub fn most_recent_id(&self) -> String {
method has_invocation_in_dir (line 189) | pub fn has_invocation_in_dir(&self, dir: &str, interner: &ThreadedRode...
method has_invocation_in_workspace (line 197) | pub fn has_invocation_in_workspace(&self, prefix: &str, interner: &Thr...
method has_invocation_on_host (line 205) | pub fn has_invocation_on_host(&self, hostname: &str, interner: &Thread...
method has_invocation_in_session (line 213) | pub fn has_invocation_in_session(&self, session: &str) -> bool {
type IndexFilterMode (line 220) | pub enum IndexFilterMode {
type QueryContext (line 235) | pub struct QueryContext {
type FrecencyMap (line 244) | type FrecencyMap = Arc<HashMap<Arc<str>, u32>>;
type SearchIndex (line 254) | pub struct SearchIndex {
method new (line 271) | pub fn new() -> Self {
method add_history (line 290) | pub fn add_history(&self, history: &History) {
method add_histories (line 313) | pub fn add_histories(&self, histories: &[History]) {
method command_count (line 320) | pub fn command_count(&self) -> usize {
method nucleo_item_count (line 325) | pub async fn nucleo_item_count(&self) -> u32 {
method search (line 334) | pub async fn search(
method rebuild_frecency (line 396) | pub async fn rebuild_frecency(&self, search_settings: &Search) {
method build_filter (line 420) | fn build_filter(&self, mode: &IndexFilterMode) -> Option<atuin_nucleo:...
method build_scorer (line 458) | fn build_scorer(frecency_map: Option<FrecencyMap>) -> Option<atuin_nuc...
method default (line 469) | fn default() -> Self {
function make_history (line 479) | fn make_history(command: &str, cwd: &str, timestamp: OffsetDateTime) -> ...
function frecency_data_compute (line 489) | fn frecency_data_compute() {
function frecency_data_compute_with_multipliers (line 516) | fn frecency_data_compute_with_multipliers() {
function command_data_add_invocation (line 559) | fn command_data_add_invocation() {
function command_data_filters (line 584) | fn command_data_filters() {
function search_index_add_and_search (line 637) | async fn search_index_add_and_search() {
FILE: crates/atuin-daemon/src/server.rs
function run_grpc_server (line 17) | pub async fn run_grpc_server(
function run_grpc_server (line 117) | pub async fn run_grpc_server(
FILE: crates/atuin-daemon/tests/lifecycle.rs
function start_test_daemon (line 23) | async fn start_test_daemon() -> (HistoryClient, DaemonHandle, TempDir) {
function test_status (line 113) | async fn test_status() {
function test_start_end_history (line 124) | async fn test_start_end_history() {
function test_end_unknown_history_fails (line 149) | async fn test_end_unknown_history_fails() {
function test_shutdown (line 159) | async fn test_shutdown() {
FILE: crates/atuin-dotfiles/src/shell.rs
type Alias (line 16) | pub struct Alias {
type Var (line 22) | pub struct Var {
method serialize (line 34) | pub fn serialize(&self, output: &mut Vec<u8>) -> Result<()> {
method deserialize (line 44) | pub fn deserialize(bytes: &mut decode::Bytes) -> Result<Self> {
function parse_alias (line 79) | pub fn parse_alias(line: &str) -> Option<Alias> {
function existing_aliases (line 116) | pub fn existing_aliases(shell: Option<Shell>) -> Result<Vec<Alias>, Shel...
function import_aliases (line 140) | pub async fn import_aliases(store: &AliasStore) -> Result<Vec<Alias>> {
function test_parse_simple_alias (line 165) | fn test_parse_simple_alias() {
function test_parse_quoted_alias (line 172) | fn test_parse_quoted_alias() {
function test_parse_quoted_alias_equals (line 188) | fn test_parse_quoted_alias_equals() {
function test_parse_fish (line 196) | fn test_parse_fish() {
function test_parse_with_fortune (line 213) | fn test_parse_with_fortune() {
FILE: crates/atuin-dotfiles/src/shell/bash.rs
function cached_aliases (line 5) | async fn cached_aliases(path: PathBuf, store: &AliasStore) -> String {
function cached_vars (line 19) | async fn cached_vars(path: PathBuf, store: &VarStore) -> String {
function alias_config (line 40) | pub async fn alias_config(store: &AliasStore) -> String {
function var_config (line 55) | pub async fn var_config(store: &VarStore) -> String {
FILE: crates/atuin-dotfiles/src/shell/fish.rs
function cached_aliases (line 6) | async fn cached_aliases(path: PathBuf, store: &AliasStore) -> String {
function cached_vars (line 20) | async fn cached_vars(path: PathBuf, store: &VarStore) -> String {
function alias_config (line 41) | pub async fn alias_config(store: &AliasStore) -> String {
function var_config (line 56) | pub async fn var_config(store: &VarStore) -> String {
FILE: crates/atuin-dotfiles/src/shell/powershell.rs
function cached_aliases (line 5) | async fn cached_aliases(path: PathBuf, store: &AliasStore) -> String {
function cached_vars (line 19) | async fn cached_vars(path: PathBuf, store: &VarStore) -> String {
function alias_config (line 40) | pub async fn alias_config(store: &AliasStore) -> String {
function var_config (line 55) | pub async fn var_config(store: &VarStore) -> String {
function format_alias (line 70) | pub fn format_alias(alias: &Alias) -> String {
function format_var (line 90) | pub fn format_var(var: &Var) -> String {
function secure_command (line 101) | fn secure_command(command: &str) -> String {
function aliases (line 113) | fn aliases() {
function vars (line 142) | fn vars() {
function invoke_expression (line 163) | fn invoke_expression() {
FILE: crates/atuin-dotfiles/src/shell/xonsh.rs
function cached_aliases (line 5) | async fn cached_aliases(path: PathBuf, store: &AliasStore) -> String {
function cached_vars (line 19) | async fn cached_vars(path: PathBuf, store: &VarStore) -> String {
function alias_config (line 40) | pub async fn alias_config(store: &AliasStore) -> String {
function var_config (line 55) | pub async fn var_config(store: &VarStore) -> String {
FILE: crates/atuin-dotfiles/src/shell/zsh.rs
function cached_aliases (line 5) | async fn cached_aliases(path: PathBuf, store: &AliasStore) -> String {
function cached_vars (line 19) | async fn cached_vars(path: PathBuf, store: &VarStore) -> String {
function alias_config (line 40) | pub async fn alias_config(store: &AliasStore) -> String {
function var_config (line 55) | pub async fn var_config(store: &VarStore) -> String {
FILE: crates/atuin-dotfiles/src/store.rs
constant CONFIG_SHELL_ALIAS_VERSION (line 17) | const CONFIG_SHELL_ALIAS_VERSION: &str = "v0";
constant CONFIG_SHELL_ALIAS_TAG (line 18) | const CONFIG_SHELL_ALIAS_TAG: &str = "config-shell-alias";
constant CONFIG_SHELL_ALIAS_FIELD_MAX_LEN (line 19) | const CONFIG_SHELL_ALIAS_FIELD_MAX_LEN: usize = 20000;
type AliasRecord (line 25) | pub enum AliasRecord {
method serialize (line 31) | pub fn serialize(&self) -> Result<DecryptedData> {
method deserialize (line 55) | pub fn deserialize(data: &DecryptedData, version: &str) -> Result<Self> {
type AliasStore (line 127) | pub struct AliasStore {
method new (line 135) | pub fn new(store: SqliteStore, host_id: HostId, encryption_key: [u8; 3...
method posix (line 143) | pub async fn posix(&self) -> Result<String> {
method xonsh (line 148) | pub async fn xonsh(&self) -> Result<String> {
method powershell (line 153) | pub async fn powershell(&self) -> Result<String> {
method format_posix (line 158) | fn format_posix(aliases: &[Alias]) -> String {
method format_xonsh (line 172) | fn format_xonsh(aliases: &[Alias]) -> String {
method format_powershell (line 182) | fn format_powershell(aliases: &[Alias]) -> String {
method build (line 192) | pub async fn build(&self) -> Result<()> {
method set (line 221) | pub async fn set(&self, name: &str, value: &str) -> Result<()> {
method delete (line 260) | pub async fn delete(&self, name: &str) -> Result<()> {
method aliases (line 296) | pub async fn aliases(&self) -> Result<Vec<Alias>> {
function test_local_timeout (line 327) | pub(crate) fn test_local_timeout() -> f64 {
function encode_decode (line 348) | fn encode_decode() {
function build_aliases (line 365) | async fn build_aliases() {
FILE: crates/atuin-dotfiles/src/store/var.rs
constant DOTFILES_VAR_VERSION (line 16) | const DOTFILES_VAR_VERSION: &str = "v0";
constant DOTFILES_VAR_TAG (line 17) | const DOTFILES_VAR_TAG: &str = "dotfiles-var";
constant DOTFILES_VAR_LEN (line 18) | const DOTFILES_VAR_LEN: usize = 20000;
type VarRecord (line 21) | pub enum VarRecord {
method serialize (line 27) | pub fn serialize(&self) -> Result<DecryptedData> {
method deserialize (line 49) | pub fn deserialize(data: &DecryptedData, version: &str) -> Result<Self> {
type VarStore (line 102) | pub struct VarStore {
method new (line 110) | pub fn new(store: SqliteStore, host_id: HostId, encryption_key: [u8; 3...
method escape_posix_value (line 120) | fn escape_posix_value(value: &str) -> String {
method escape_fish_value (line 142) | fn escape_fish_value(value: &str) -> String {
method escape_xonsh_value (line 157) | fn escape_xonsh_value(value: &str) -> String {
method xonsh (line 170) | pub async fn xonsh(&self) -> Result<String> {
method fish (line 175) | pub async fn fish(&self) -> Result<String> {
method posix (line 180) | pub async fn posix(&self) -> Result<String> {
method powershell (line 185) | pub async fn powershell(&self) -> Result<String> {
method format_xonsh (line 190) | fn format_xonsh(env: &[Var]) -> String {
method format_fish (line 201) | fn format_fish(env: &[Var]) -> String {
method format_posix (line 212) | fn format_posix(env: &[Var]) -> String {
method format_powershell (line 227) | fn format_powershell(env: &[Var]) -> String {
method build (line 237) | pub async fn build(&self) -> Result<()> {
method set (line 267) | pub async fn set(&self, name: &str, value: &str, export: bool) -> Resu...
method delete (line 307) | pub async fn delete(&self, name: &str) -> Result<()> {
method vars (line 343) | pub async fn vars(&self) -> Result<Vec<Var>> {
function encode_decode (line 385) | fn encode_decode() {
function test_escape_posix_value (line 405) | fn test_escape_posix_value() {
function test_escape_fish_value (line 441) | fn test_escape_fish_value() {
function test_escape_xonsh_value (line 455) | fn test_escape_xonsh_value() {
function build_vars (line 479) | async fn build_vars() {
function test_var_generation_with_spaces (line 517) | async fn test_var_generation_with_spaces() {
FILE: crates/atuin-hex/src/lib.rs
type Cmd (line 6) | pub enum Cmd {
type Init (line 12) | pub struct Init {
method run (line 41) | fn run(self) -> Result<(), String> {
type Shell (line 21) | enum Shell {
method as_str (line 31) | fn as_str(self) -> &'static str {
function run (line 49) | pub fn run(cmd: Option<Cmd>) {
function detect_shell (line 61) | fn detect_shell(cli_shell: Option<Shell>) -> Result<Shell, String> {
function shell_from_name (line 84) | fn shell_from_name(name: &str) -> Option<Shell> {
function init_command (line 101) | fn init_command(shell: Shell) -> String {
function render_init (line 105) | fn render_init(shell: Shell) -> String {
function main (line 157) | pub(crate) fn main() {
type ParserMsg (line 172) | enum ParserMsg {
function main (line 178) | pub(crate) fn main() {
function socket_path (line 186) | fn socket_path() -> std::path::PathBuf {
function encode_screen (line 203) | fn encode_screen(parser: &vt100::Parser) -> Vec<u8> {
function handle_parser_msg (line 223) | fn handle_parser_msg(parser: &mut vt100::Parser, msg: ParserMsg) {
function run (line 233) | fn run() -> eyre::Result<()> {
function process_exit_code (line 412) | fn process_exit_code(code: u32) -> i32 {
function process_exit_code_preserves_valid_values (line 421) | fn process_exit_code_preserves_valid_values() {
function process_exit_code_defaults_when_out_of_range (line 428) | fn process_exit_code_defaults_when_out_of_range() {
function shell_from_name_handles_paths (line 439) | fn shell_from_name_handles_paths() {
function init_command_is_bootstrap_only (line 446) | fn init_command_is_bootstrap_only() {
function posix_init_uses_exec_and_tmux_guard (line 452) | fn posix_init_uses_exec_and_tmux_guard() {
function fish_init_uses_source (line 460) | fn fish_init_uses_source() {
FILE: crates/atuin-hex/src/osc133.rs
type Event (line 27) | pub enum Event {
type Zone (line 44) | pub enum Zone {
constant ESC (line 60) | const ESC: u8 = 0x1B;
constant BEL (line 61) | const BEL: u8 = 0x07;
constant BACKSLASH (line 62) | const BACKSLASH: u8 = b'\\';
constant RIGHT_BRACKET (line 63) | const RIGHT_BRACKET: u8 = b']';
constant PARAM_BUF_CAP (line 69) | const PARAM_BUF_CAP: usize = 32;
type State (line 76) | enum State {
type Parser (line 94) | pub struct Parser {
method new (line 110) | pub fn new() -> Self {
method zone (line 122) | pub fn zone(&self) -> Zone {
method push (line 132) | pub fn push(&mut self, data: &[u8], mut on_event: impl FnMut(Event)) {
method dispatch (line 177) | fn dispatch(&mut self, on_event: &mut impl FnMut(Event)) {
method default (line 102) | fn default() -> Self {
function parse_events (line 226) | fn parse_events(data: &[u8]) -> Vec<Event> {
function detect_prompt_start_bel (line 236) | fn detect_prompt_start_bel() {
function detect_prompt_start_st (line 242) | fn detect_prompt_start_st() {
function detect_command_start_bel (line 248) | fn detect_command_start_bel() {
function detect_command_start_st (line 254) | fn detect_command_start_st() {
function detect_command_executed_bel (line 260) | fn detect_command_executed_bel() {
function detect_command_executed_st (line 266) | fn detect_command_executed_st() {
function detect_command_finished_no_exit_code (line 272) | fn detect_command_finished_no_exit_code() {
function detect_command_finished_exit_zero (line 281) | fn detect_command_finished_exit_zero() {
function detect_command_finished_exit_nonzero (line 290) | fn detect_command_finished_exit_nonzero() {
function detect_command_finished_negative_exit_code (line 301) | fn detect_command_finished_negative_exit_code() {
function detect_command_finished_exit_code_st (line 312) | fn detect_command_finished_exit_code_st() {
function invalid_exit_code_yields_none (line 323) | fn invalid_exit_code_yields_none() {
function zone_starts_unknown (line 334) | fn zone_starts_unknown() {
function full_zone_cycle (line 340) | fn full_zone_cycle() {
function multiple_events_single_push (line 370) | fn multiple_events_single_push() {
function split_esc_and_bracket (line 387) | fn split_esc_and_bracket() {
function split_mid_param (line 399) | fn split_mid_param() {
function split_before_terminator (line 416) | fn split_before_terminator() {
function split_esc_backslash_terminator (line 428) | fn split_esc_backslash_terminator() {
function normal_text_before_and_after (line 442) | fn normal_text_before_and_after() {
function non_133_osc_ignored (line 451) | fn non_133_osc_ignored() {
function osc_7_ignored (line 458) | fn osc_7_ignored() {
function unknown_command_ignored (line 466) | fn unknown_command_ignored() {
function esc_followed_by_non_bracket (line 474) | fn esc_followed_by_non_bracket() {
function lone_esc_at_end_of_chunk (line 481) | fn lone_esc_at_end_of_chunk() {
function truncated_133_prefix (line 494) | fn truncated_133_prefix() {
function empty_osc (line 501) | fn empty_osc() {
function very_long_osc_does_not_panic (line 509) | fn very_long_osc_does_not_panic() {
function empty_input (line 521) | fn empty_input() {
function only_normal_text (line 526) | fn only_normal_text() {
function repeated_prompt_cycle (line 534) | fn repeated_prompt_cycle() {
function byte_at_a_time (line 558) | fn byte_at_a_time() {
function mixed_bel_and_st_terminators (line 578) | fn mixed_bel_and_st_terminators() {
function parser_default (line 595) | fn parser_default() {
function zone_default (line 601) | fn zone_default() {
function d_with_semicolon_but_empty_code (line 608) | fn d_with_semicolon_but_empty_code() {
function back_to_back_osc_no_gap (line 620) | fn back_to_back_osc_no_gap() {
function csi_sequences_ignored (line 629) | fn csi_sequences_ignored() {
function large_exit_code (line 639) | fn large_exit_code() {
function overflow_exit_code_yields_none (line 650) | fn overflow_exit_code_yields_none() {
FILE: crates/atuin-history/benches/smart_sort.rs
function main (line 6) | fn main() {
function smart_sort (line 13) | fn smart_sort(lines: usize) {
FILE: crates/atuin-history/src/sort.rs
type ScoredHistory (line 3) | type ScoredHistory = (f64, History);
function sort (line 9) | pub fn sort(query: &str, input: Vec<History>) -> Vec<History> {
FILE: crates/atuin-history/src/stats.rs
type Stats (line 10) | pub struct Stats {
function first_non_whitespace (line 16) | fn first_non_whitespace(s: &str) -> Option<usize> {
function first_whitespace (line 24) | fn first_whitespace(s: &str) -> usize {
function interesting_command (line 32) | fn interesting_command<'a>(settings: &Settings, mut command: &'a str) ->...
function split_at_pipe (line 73) | fn split_at_pipe(command: &str) -> Vec<&str> {
function strip_leading_env_vars (line 112) | fn strip_leading_env_vars(command: &str) -> &str {
function pretty_print (line 171) | pub fn pretty_print(stats: Stats, ngram_size: usize, theme: &Theme) {
function compute (line 248) | pub fn compute(
function ignored_env_vars (line 316) | fn ignored_env_vars() {
function ignored_commands (line 331) | fn ignored_commands() {
function interesting_commands (line 354) | fn interesting_commands() {
function interesting_commands_spaces (line 371) | fn interesting_commands_spaces() {
function interesting_commands_spaces_subcommand (line 396) | fn interesting_commands_spaces_subcommand() {
function interesting_commands_spaces_both (line 426) | fn interesting_commands_spaces_both() {
function split_simple (line 453) | fn split_simple() {
function split_multi (line 458) | fn split_multi() {
function split_simple_quoted (line 466) | fn split_simple_quoted() {
function split_multi_quoted (line 474) | fn split_multi_quoted() {
function escaped_pipes (line 482) | fn escaped_pipes() {
function emoji (line 490) | fn emoji() {
function starts_with_pipe (line 498) | fn starts_with_pipe() {
function starts_with_spaces_and_pipe (line 506) | fn starts_with_spaces_and_pipe() {
function strip_leading_env_vars_simple (line 514) | fn strip_leading_env_vars_simple() {
function strip_leading_env_vars_quoted_single (line 522) | fn strip_leading_env_vars_quoted_single() {
function strip_leading_env_vars_quoted_double (line 527) | fn strip_leading_env_vars_quoted_double() {
function strip_leading_env_vars_quoted_single_and_double (line 535) | fn strip_leading_env_vars_quoted_single_and_double() {
function strip_leading_env_vars_emojis (line 543) | fn strip_leading_env_vars_emojis() {
function strip_leading_env_vars_name_same_as_command (line 551) | fn strip_leading_env_vars_name_same_as_command() {
FILE: crates/atuin-kv/migrations/20250501160746_create_kv_db.up.sql
type kv (line 2) | CREATE TABLE
type idx_kv_namespace (line 10) | CREATE INDEX idx_kv_namespace ON kv (namespace)
type idx_kv (line 12) | CREATE UNIQUE INDEX idx_kv ON kv (namespace, key)
FILE: crates/atuin-kv/src/database.rs
type Database (line 17) | pub struct Database {
method new (line 22) | pub async fn new(path: impl AsRef<Path>, timeout: f64) -> Result<Self> {
method sqlite_version (line 56) | pub async fn sqlite_version(&self) -> Result<String> {
method setup_db (line 62) | async fn setup_db(pool: &SqlitePool) -> Result<()> {
method save_raw (line 70) | async fn save_raw(tx: &mut sqlx::Transaction<'_, sqlx::Sqlite>, e: &Kv...
method delete_raw (line 88) | async fn delete_raw(
method save (line 101) | pub async fn save(&self, e: &KvEntry) -> Result<()> {
method delete (line 110) | pub async fn delete(&self, namespace: &str, key: &str) -> Result<()> {
method query_kv_entry (line 120) | fn query_kv_entry(row: SqliteRow) -> KvEntry {
method load (line 132) | pub async fn load(&self, namespace: &str, key: &str) -> Result<Option<...
method list (line 145) | pub async fn list(&self, namespace: Option<&str>) -> Result<Vec<KvEntr...
function test_list (line 170) | async fn test_list() {
function test_save_load (line 191) | async fn test_save_load() {
function test_delete (line 212) | async fn test_delete() {
FILE: crates/atuin-kv/src/store.rs
type KvStore (line 17) | pub struct KvStore {
method new (line 25) | pub fn new(
method set (line 39) | pub async fn set(&self, namespace: &str, key: &str, value: &str) -> Re...
method get (line 59) | pub async fn get(&self, namespace: &str, key: &str) -> Result<Option<S...
method delete (line 64) | pub async fn delete(&self, namespace: &str, keys: &[String]) -> Result...
method list (line 79) | pub async fn list(&self, namespace: Option<&str>) -> Result<Vec<KvEntr...
method push_record (line 85) | async fn push_record(&self, record: KvRecord) -> Result<(RecordId, Rec...
method build (line 110) | pub async fn build(&self) -> Result<()> {
function setup (line 170) | async fn setup() -> Result<KvStore> {
function test_kv_store (line 179) | async fn test_kv_store() -> Result<()> {
FILE: crates/atuin-kv/src/store/entry.rs
type KvEntry (line 4) | pub struct KvEntry {
FILE: crates/atuin-kv/src/store/record.rs
constant KV_VERSION (line 5) | pub const KV_VERSION: &str = "v1";
constant KV_TAG (line 6) | pub const KV_TAG: &str = "kv";
constant KV_VAL_MAX_LEN (line 7) | pub const KV_VAL_MAX_LEN: usize = 100 * 1024;
type KvRecord (line 10) | pub struct KvRecord {
method serialize (line 17) | pub fn serialize(&self) -> Result<DecryptedData> {
method deserialize (line 36) | pub fn deserialize(data: &DecryptedData, version: &str) -> Result<Self> {
function encode_decode_some (line 110) | fn encode_decode_some() {
function encode_decode_none (line 128) | fn encode_decode_none() {
function decode_v0 (line 144) | fn decode_v0() {
FILE: crates/atuin-nucleo/bench/src/main.rs
function bench_dir (line 9) | fn bench_dir() -> PathBuf {
function checkout_linux_if_needed (line 15) | fn checkout_linux_if_needed() {
function main (line 35) | fn main() {
FILE: crates/atuin-nucleo/matcher/fuzz/fuzz_targets/fuzz_target_1.rs
type Input (line 8) | pub struct Input<'a> {
FILE: crates/atuin-nucleo/matcher/src/chars.rs
type Char (line 17) | pub(crate) trait Char: Copy + Eq + Ord + fmt::Display {
constant ASCII (line 18) | const ASCII: bool;
method char_class (line 19) | fn char_class(self, config: &Config) -> CharClass;
method char_class_and_normalize (line 20) | fn char_class_and_normalize(self, config: &Config) -> (Self, CharClass);
method normalize (line 21) | fn normalize(self, config: &Config) -> Self;
constant ASCII (line 48) | const ASCII: bool = true;
method char_class (line 50) | fn char_class(self, config: &Config) -> CharClass {
method char_class_and_normalize (line 69) | fn char_class_and_normalize(mut self, config: &Config) -> (Self, CharC...
method normalize (line 78) | fn normalize(mut self, config: &Config) -> Self {
constant ASCII (line 101) | const ASCII: bool = false;
method char_class (line 103) | fn char_class(self, config: &Config) -> CharClass {
method char_class_and_normalize (line 111) | fn char_class_and_normalize(mut self, config: &Config) -> (Self, CharC...
method normalize (line 134) | fn normalize(mut self, config: &Config) -> Self {
type AsciiChar (line 27) | pub(crate) struct AsciiChar(pub u8);
method cast (line 30) | pub fn cast(bytes: &[u8]) -> &[AsciiChar] {
method fmt (line 36) | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
function eq (line 42) | fn eq(&self, other: &AsciiChar) -> bool {
function char_class_non_ascii (line 85) | fn char_class_non_ascii(c: char) -> CharClass {
function to_lower_case (line 155) | pub fn to_lower_case(c: char) -> char {
function is_upper_case (line 164) | pub fn is_upper_case(c: char) -> bool {
type CharClass (line 175) | pub(crate) enum CharClass {
function graphemes (line 189) | pub fn graphemes(text: &str) -> impl Iterator<Item = char> + '_ {
FILE: crates/atuin-nucleo/matcher/src/chars/case_fold.rs
constant CASE_FOLDING_SIMPLE (line 9) | pub const CASE_FOLDING_SIMPLE: &'static [(char, char)] = &[
FILE: crates/atuin-nucleo/matcher/src/chars/normalize.rs
function normalize (line 27) | pub fn normalize(c: char) -> char {
function check_conversions (line 899) | fn check_conversions(pairs: &[(char, char)]) {
function general (line 907) | fn general() {
function invisible_chars (line 935) | fn invisible_chars() {
function boundary_cases (line 941) | fn boundary_cases() {
function unchanged_outside_blocks (line 962) | fn unchanged_outside_blocks() {
FILE: crates/atuin-nucleo/matcher/src/config.rs
type Config (line 7) | pub struct Config {
constant DEFAULT (line 34) | pub const DEFAULT: Self = {
method set_match_paths (line 49) | pub fn set_match_paths(&mut self) {
method match_paths (line 60) | pub const fn match_paths(mut self) -> Self {
FILE: crates/atuin-nucleo/matcher/src/debug.rs
method fmt (line 5) | fn fmt(&self, f: &mut Formatter<'_>) -> Result {
method fmt (line 11) | fn fmt(&self, f: &mut Formatter<'_>) -> Result {
FILE: crates/atuin-nucleo/matcher/src/exact.rs
method substring_match_1_ascii (line 9) | pub(crate) fn substring_match_1_ascii<const INDICES: bool>(
method substring_match_ascii_with_prefilter (line 64) | pub(crate) fn substring_match_ascii_with_prefilter(
method substring_match_ascii (line 99) | pub(crate) fn substring_match_ascii<const INDICES: bool>(
method substring_match_1_non_ascii (line 185) | pub(crate) fn substring_match_1_non_ascii<const INDICES: bool>(
method substring_match_non_ascii (line 222) | pub(crate) fn substring_match_non_ascii<const INDICES: bool, N>(
FILE: crates/atuin-nucleo/matcher/src/fuzzy_greedy.rs
method fuzzy_match_greedy_ (line 7) | pub(crate) fn fuzzy_match_greedy_<const INDICES: bool, H: Char + Partial...
FILE: crates/atuin-nucleo/matcher/src/fuzzy_optimal.rs
method fuzzy_match_optimal (line 12) | pub(crate) fn fuzzy_match_optimal<const INDICES: bool, H: Char + Partial...
constant UNMATCHED (line 60) | const UNMATCHED: ScoreCell = ScoreCell {
function next_m_cell (line 69) | fn next_m_cell(p_score: u16, bonus: u16, m_cell: ScoreCell) -> ScoreCell {
function p_score (line 100) | fn p_score(prev_p_score: u16, prev_m_score: u16) -> (u16, bool) {
function setup (line 111) | fn setup<const INDICES: bool, N: Char>(
function score_row (line 183) | fn score_row<const FIRST_ROW: bool, const INDICES: bool, N: Char>(
function populate_matrix (line 269) | fn populate_matrix<const INDICES: bool, N: Char>(&mut self, needle: &[N]...
function reconstruct_optimal_path (line 300) | fn reconstruct_optimal_path(
FILE: crates/atuin-nucleo/matcher/src/lib.rs
type Matcher (line 154) | pub struct Matcher {
method fmt (line 171) | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
method new (line 191) | pub fn new(config: Config) -> Self {
method fuzzy_match (line 206) | pub fn fuzzy_match(&mut self, haystack: Utf32Str<'_>, needle: Utf32Str...
method fuzzy_indices (line 220) | pub fn fuzzy_indices(
method fuzzy_matcher_impl (line 230) | fn fuzzy_matcher_impl<const INDICES: bool>(
method fuzzy_match_greedy (line 340) | pub fn fuzzy_match_greedy(
method fuzzy_indices_greedy (line 356) | pub fn fuzzy_indices_greedy(
method fuzzy_match_greedy_impl (line 366) | fn fuzzy_match_greedy_impl<const INDICES: bool>(
method substring_match (line 440) | pub fn substring_match(
method substring_indices (line 456) | pub fn substring_indices(
method substring_match_impl (line 465) | fn substring_match_impl<const INDICES: bool>(
method exact_match (line 533) | pub fn exact_match(&mut self, haystack: Utf32Str<'_>, needle: Utf32Str...
method exact_indices (line 563) | pub fn exact_indices(
method prefix_match (line 598) | pub fn prefix_match(&mut self, haystack: Utf32Str<'_>, needle: Utf32St...
method prefix_indices (line 624) | pub fn prefix_indices(
method postfix_match (line 655) | pub fn postfix_match(&mut self, haystack: Utf32Str<'_>, needle: Utf32S...
method postfix_indices (line 681) | pub fn postfix_indices(
method exact_match_impl (line 707) | fn exact_match_impl<const INDICES: bool>(
method clone (line 162) | fn clone(&self) -> Self {
method default (line 179) | fn default() -> Self {
FILE: crates/atuin-nucleo/matcher/src/matrix.rs
constant MAX_MATRIX_SIZE (line 9) | const MAX_MATRIX_SIZE: usize = 100 * 1024;
constant MAX_HAYSTACK_LEN (line 12) | const MAX_HAYSTACK_LEN: usize = 2048;
constant MAX_NEEDLE_LEN (line 13) | const MAX_NEEDLE_LEN: usize = 2048;
type MatrixLayout (line 15) | struct MatrixLayout<C: Char> {
function new (line 27) | fn new(haystack_len: usize, needle_len: usize) -> MatrixLayout<C> {
function fieds_from_ptr (line 64) | unsafe fn fieds_from_ptr(
constant _SIZE_CHECK (line 92) | const _SIZE_CHECK: () = {
type ScoreCell (line 101) | pub(crate) struct ScoreCell {
type MatcherDataView (line 107) | pub(crate) struct MatcherDataView<'a, C: Char> {
type MatrixCell (line 117) | pub struct MatrixCell(pub(crate) u8);
method set (line 120) | pub fn set(&mut self, p_match: bool, m_match: bool) {
method get (line 124) | pub fn get(&self, m_matrix: bool) -> bool {
type MatcherData (line 132) | struct MatcherData {
type MatrixSlab (line 140) | pub(crate) struct MatrixSlab(NonNull<u8>);
method new (line 147) | pub fn new() -> Self {
method alloc (line 157) | pub(crate) fn alloc<C: Char>(
method drop (line 195) | fn drop(&mut self) {
FILE: crates/atuin-nucleo/matcher/src/pattern.rs
type CaseMatching (line 15) | pub enum CaseMatching {
type Normalization (line 32) | pub enum Normalization {
type AtomKind (line 46) | pub enum AtomKind {
type Atom (line 82) | pub struct Atom {
method new (line 98) | pub fn new(
method new_inner (line 108) | fn new_inner(
method parse (line 242) | pub fn parse(raw: &str, case: CaseMatching, normalize: Normalization) ...
method score (line 304) | pub fn score(&self, haystack: Utf32Str<'_>, matcher: &mut Matcher) -> ...
method indices (line 333) | pub fn indices(
method needle_text (line 370) | pub fn needle_text(&self) -> Utf32Str<'_> {
method match_list (line 381) | pub fn match_list<T: AsRef<str>>(
function pattern_atoms (line 402) | fn pattern_atoms(pattern: &str) -> impl Iterator<Item = &str> + '_ {
type Pattern (line 417) | pub struct Pattern {
method new (line 427) | pub fn new(
method parse (line 445) | pub fn parse(pattern: &str, case_matching: CaseMatching, normalize: No...
method match_list (line 463) | pub fn match_list<T: AsRef<str>>(
method score (line 489) | pub fn score(&self, haystack: Utf32Str<'_>, matcher: &mut Matcher) -> ...
method indices (line 519) | pub fn indices(
method reparse (line 538) | pub fn reparse(
method clone (line 557) | fn clone(&self) -> Self {
method clone_from (line 563) | fn clone_from(&mut self, source: &Self) {
FILE: crates/atuin-nucleo/matcher/src/pattern/tests.rs
function negative (line 4) | fn negative() {
function pattern_kinds (line 24) | fn pattern_kinds() {
function case_matching (line 48) | fn case_matching() {
function escape (line 87) | fn escape() {
function pattern_atoms (line 117) | fn pattern_atoms() {
FILE: crates/atuin-nucleo/matcher/src/prefilter.rs
function find_ascii_ignore_case (line 8) | fn find_ascii_ignore_case(c: u8, haystack: &[u8]) -> Option<usize> {
function find_ascii_ignore_case_rev (line 17) | fn find_ascii_ignore_case_rev(c: u8, haystack: &[u8]) -> Option<usize> {
method prefilter_ascii (line 26) | pub(crate) fn prefilter_ascii(
method prefilter_non_ascii (line 69) | pub(crate) fn prefilter_non_ascii(
FILE: crates/atuin-nucleo/matcher/src/score.rs
constant SCORE_MATCH (line 6) | pub(crate) const SCORE_MATCH: u16 = 16;
constant PENALTY_GAP_START (line 7) | pub(crate) const PENALTY_GAP_START: u16 = 3;
constant PENALTY_GAP_EXTENSION (line 8) | pub(crate) const PENALTY_GAP_EXTENSION: u16 = 1;
constant PREFIX_BONUS_SCALE (line 11) | pub(crate) const PREFIX_BONUS_SCALE: u16 = 2;
constant MAX_PREFIX_BONUS (line 12) | pub(crate) const MAX_PREFIX_BONUS: u16 = BONUS_BOUNDARY;
constant BONUS_BOUNDARY (line 20) | pub(crate) const BONUS_BOUNDARY: u16 = SCORE_MATCH / 2;
constant BONUS_CAMEL123 (line 31) | pub(crate) const BONUS_CAMEL123: u16 = BONUS_BOUNDARY - PENALTY_GAP_START;
constant BONUS_NON_WORD (line 36) | pub(crate) const BONUS_NON_WORD: u16 = BONUS_BOUNDARY;
constant BONUS_CONSECUTIVE (line 41) | pub(crate) const BONUS_CONSECUTIVE: u16 = PENALTY_GAP_START + PENALTY_GA...
constant BONUS_FIRST_CHAR_MULTIPLIER (line 48) | pub(crate) const BONUS_FIRST_CHAR_MULTIPLIER: u16 = 2;
method bonus_for (line 52) | pub(crate) fn bonus_for(&self, prev_class: CharClass, class: CharClass) ...
method bonus_for (line 78) | pub(crate) fn bonus_for(&self, prev_class: CharClass, class: CharClass) ...
method calculate_score (line 82) | pub(crate) fn calculate_score<const INDICES: bool, H: Char + PartialEq<N...
FILE: crates/atuin-nucleo/matcher/src/tests.rs
type Algorithm (line 13) | enum Algorithm {
function assert_matches (line 22) | fn assert_matches(
function assert_not_matches_with (line 87) | fn assert_not_matches_with(
function assert_not_matches (line 127) | pub fn assert_not_matches(normalize: bool, case_sensitive: bool, cases: ...
constant BONUS_BOUNDARY_WHITE (line 136) | const BONUS_BOUNDARY_WHITE: u16 = Config::DEFAULT.bonus_boundary_white;
constant BONUS_BOUNDARY_DELIMITER (line 137) | const BONUS_BOUNDARY_DELIMITER: u16 = Config::DEFAULT.bonus_boundary_del...
function test_fuzzy (line 140) | fn test_fuzzy() {
function empty_needle (line 249) | fn empty_needle() {
function test_substring (line 261) | fn test_substring() {
function test_substring_case_sensitive (line 390) | fn test_substring_case_sensitive() {
function test_fuzzy_case_sensitive (line 422) | fn test_fuzzy_case_sensitive() {
function test_normalize (line 464) | fn test_normalize() {
function test_unicode (line 511) | fn test_unicode() {
function test_long_str (line 554) | fn test_long_str() {
function test_casing (line 571) | fn test_casing() {
function test_optimal (line 612) | fn test_optimal() {
function test_reject (line 659) | fn test_reject() {
function test_prefer_prefix (line 700) | fn test_prefer_prefix() {
function test_single_char_needle (line 729) | fn test_single_char_needle() {
function umlaut (line 759) | fn umlaut() {
FILE: crates/atuin-nucleo/matcher/src/utf32_str.rs
function has_ascii_graphemes (line 20) | fn has_ascii_graphemes(string: &str) -> bool {
type Utf32Str (line 96) | pub enum Utf32Str<'a> {
function new (line 106) | pub fn new(str: &'a str, buf: &'a mut Vec<char>) -> Self {
function len (line 118) | pub fn len(self) -> usize {
function is_empty (line 127) | pub fn is_empty(self) -> bool {
function slice (line 137) | pub fn slice(self, range: impl RangeBounds<usize>) -> Utf32Str<'a> {
function leading_white_space (line 156) | pub(crate) fn leading_white_space(self) -> usize {
function trailing_white_space (line 171) | pub(crate) fn trailing_white_space(self) -> usize {
function slice_u32 (line 189) | pub fn slice_u32(self, range: impl RangeBounds<u32>) -> Utf32Str<'a> {
function is_ascii (line 211) | pub fn is_ascii(self) -> bool {
function get (line 216) | pub fn get(self, n: u32) -> char {
function last (line 226) | pub(crate) fn last(self) -> char {
function first (line 236) | pub(crate) fn first(self) -> char {
function chars (line 244) | pub fn chars(self) -> Chars<'a> {
function fmt (line 253) | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
function fmt (line 265) | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
type Chars (line 273) | pub enum Chars<'a> {
type Item (line 279) | type Item = char;
method next (line 281) | fn next(&mut self) -> Option<Self::Item> {
method next_back (line 290) | fn next_back(&mut self) -> Option<Self::Item> {
type Utf32String (line 302) | pub enum Utf32String {
method len (line 319) | pub fn len(&self) -> usize {
method is_empty (line 328) | pub fn is_empty(&self) -> bool {
method slice (line 338) | pub fn slice(&self, range: impl RangeBounds<usize>) -> Utf32Str {
method slice_u32 (line 358) | pub fn slice_u32(&self, range: impl RangeBounds<u32>) -> Utf32Str {
method from (line 382) | fn from(value: &str) -> Self {
method from (line 392) | fn from(value: Box<str>) -> Self {
method from (line 403) | fn from(value: String) -> Self {
method from (line 410) | fn from(value: Cow<'a, str>) -> Self {
method fmt (line 419) | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
method fmt (line 425) | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
method default (line 311) | fn default() -> Self {
FILE: crates/atuin-nucleo/matcher/src/utf32_str/tests.rs
function test_utf32str_ascii (line 4) | fn test_utf32str_ascii() {
function test_grapheme_truncation (line 30) | fn test_grapheme_truncation() {
FILE: crates/atuin-nucleo/src/boxcar.rs
constant BUCKETS (line 33) | const BUCKETS: u32 = u32::BITS - SKIP_BUCKET;
constant MAX_ENTRIES (line 34) | const MAX_ENTRIES: u32 = u32::MAX - SKIP;
type Vec (line 37) | pub(crate) struct Vec<T> {
function with_capacity (line 53) | pub fn with_capacity(capacity: u32, columns: u32) -> Vec<T> {
function columns (line 74) | pub fn columns(&self) -> u32 {
function count (line 80) | pub fn count(&self) -> u32 {
function get_unchecked (line 92) | pub unsafe fn get_unchecked(&self, index: u32) -> Item<'_, T> {
function get (line 113) | pub fn get(&self, index: u32) -> Option<Item<'_, T>> {
function push (line 141) | pub fn push(&self, value: T, fill_columns: impl FnOnce(&T, &mut [Utf32St...
function extend (line 187) | pub fn extend<I>(&self, values: I, fill_columns: impl Fn(&T, &mut [Utf32...
function get_or_alloc (line 275) | fn get_or_alloc(bucket: &Bucket<T>, len: u32, cols: u32) -> *mut Entry<T> {
function snapshot (line 294) | pub unsafe fn snapshot(&self, start: u32) -> Iter<'_, T> {
function par_snapshot (line 311) | pub unsafe fn par_snapshot(&self, start: u32) -> ParIter<'_, T> {
method drop (line 327) | fn drop(&mut self) {
type SnapshotItem (line 341) | type SnapshotItem<'v, T> = (u32, Option<Item<'v, T>>);
type Iter (line 343) | pub struct Iter<'v, T> {
function end (line 350) | pub fn end(&self) -> u32 {
type Item (line 356) | type Item = SnapshotItem<'v, T>;
method size_hint (line 357) | fn size_hint(&self) -> (usize, Option<usize>) {
method next (line 364) | fn next(&mut self) -> Option<SnapshotItem<'v, T>> {
method next_back (line 415) | fn next_back(&mut self) -> Option<Self::Item> {
type ParIter (line 420) | pub struct ParIter<'v, T> {
function end (line 426) | pub fn end(&self) -> u32 {
type Item (line 432) | type Item = SnapshotItem<'v, T>;
function drive_unindexed (line 434) | fn drive_unindexed<C>(self, consumer: C) -> C::Result
function opt_len (line 441) | fn opt_len(&self) -> Option<usize> {
function len (line 447) | fn len(&self) -> usize {
function drive (line 451) | fn drive<C: rayon::iter::plumbing::Consumer<Self::Item>>(self, consumer:...
function with_producer (line 455) | fn with_producer<CB>(self, callback: CB) -> CB::Output
type ParIterProducer (line 467) | struct ParIterProducer<'v, T: Send> {
type Item (line 474) | type Item = SnapshotItem<'v, T>;
type IntoIter (line 475) | type IntoIter = Iter<'v, T>;
function into_iter (line 477) | fn into_iter(self) -> Self::IntoIter {
function split_at (line 487) | fn split_at(self, index: usize) -> (Self, Self) {
type Bucket (line 505) | struct Bucket<T> {
function layout (line 510) | fn layout(len: u32, layout: Layout) -> Layout {
function alloc (line 515) | unsafe fn alloc(len: u32, cols: u32) -> *mut Entry<T> {
function dealloc (line 530) | unsafe fn dealloc(entries: *mut Entry<T>, len: u32, cols: u32) {
function get (line 545) | unsafe fn get(entries: *mut Entry<T>, idx: u32, cols: u32) -> *mut Entry...
function new (line 551) | fn new(entries: *mut Entry<T>) -> Bucket<T> {
type Entry (line 559) | struct Entry<T> {
function layout (line 566) | fn layout(cols: u32) -> Layout {
function matcher_cols_raw (line 575) | unsafe fn matcher_cols_raw<'a>(
function matcher_cols_mut (line 588) | unsafe fn matcher_cols_mut<'a>(ptr: *mut Entry<T>, cols: u32) -> &'a mut...
function read (line 600) | unsafe fn read<'a>(ptr: *mut Entry<T>, cols: u32) -> Item<'a, T> {
type Location (line 617) | struct Location {
method of (line 632) | fn of(index: u32) -> Location {
method bucket_len (line 646) | fn bucket_len(bucket: u32) -> u32 {
method alloc_next_bucket_entry (line 651) | fn alloc_next_bucket_entry(&self) -> u32 {
constant SKIP (line 628) | const SKIP: u32 = 32;
constant SKIP_BUCKET (line 629) | const SKIP_BUCKET: u32 = (u32::BITS - SKIP.leading_zeros()) - 1;
function location (line 661) | fn location() {
function extend_unique_bucket (line 693) | fn extend_unique_bucket() {
function extend_over_two_buckets (line 704) | fn extend_over_two_buckets() {
function extend_over_more_than_two_buckets (line 715) | fn extend_over_more_than_two_buckets() {
function extend_with_incorrect_reported_len_is_caught (line 727) | fn extend_with_incorrect_reported_len_is_caught() {
function extend_over_max_capacity (line 780) | fn extend_over_max_capacity() {
FILE: crates/atuin-nucleo/src/lib.rs
type Filter (line 36) | pub type Filter<T> = Arc<dyn Fn(&T) -> bool + Send + Sync>;
type Scorer (line 41) | pub type Scorer<T> = Arc<dyn Fn(&T, u32) -> u32 + Send + Sync>;
type Item (line 59) | pub struct Item<'a, T> {
type Injector (line 68) | pub struct Injector<T> {
method clone (line 74) | fn clone(&self) -> Self {
function push (line 85) | pub fn push(&self, value: T, fill_columns: impl FnOnce(&T, &mut [Utf32St...
function extend (line 100) | pub fn extend<I>(&self, values: I, fill_columns: impl Fn(&T, &mut [Utf32...
function injected_items (line 111) | pub fn injected_items(&self) -> u32 {
function get_unchecked (line 123) | pub unsafe fn get_unchecked(&self, index: u32) -> Item<'_, T> {
function get (line 128) | pub fn get(&self, index: u32) -> Option<Item<'_, T>> {
type Match (line 135) | pub struct Match {
type Status (line 148) | pub struct Status {
type Snapshot (line 157) | pub struct Snapshot<T: Sync + Send + 'static> {
function clear (line 165) | fn clear(&mut self, new_items: Arc<boxcar::Vec<T>>) {
function update (line 171) | fn update(&mut self, worker: &Worker<T>) {
function item_count (line 181) | pub fn item_count(&self) -> u32 {
function pattern (line 186) | pub fn pattern(&self) -> &MultiPattern {
function matched_item_count (line 191) | pub fn matched_item_count(&self) -> u32 {
function matched_items (line 201) | pub fn matched_items(
function get_item_unchecked (line 230) | pub unsafe fn get_item_unchecked(&self, index: u32) -> Item<'_, T> {
function get_item (line 241) | pub fn get_item(&self, index: u32) -> Option<Item<'_, T>> {
function matches (line 247) | pub fn matches(&self) -> &[Match] {
function get_matched_item (line 256) | pub fn get_matched_item(&self, n: u32) -> Option<Item<'_, T>> {
type State (line 265) | enum State {
method matcher_item_refs (line 274) | fn matcher_item_refs(self) -> usize {
method canceled (line 281) | fn canceled(self) -> bool {
method cleared (line 285) | fn cleared(self) -> bool {
type Nucleo (line 292) | pub struct Nucleo<T: Sync + Send + 'static> {
function new (line 330) | pub fn new(
function active_injectors (line 359) | pub fn active_injectors(&self) -> usize {
function snapshot (line 366) | pub fn snapshot(&self) -> &Snapshot<T> {
function injector (line 371) | pub fn injector(&self) -> Injector<T> {
function restart (line 389) | pub fn restart(&mut self, clear_snapshot: bool) {
function update_config (line 399) | pub fn update_config(&mut self, config: Config) {
function sort_results (line 405) | pub fn sort_results(&mut self, sort_results: bool) {
function reverse_items (line 411) | pub fn reverse_items(&mut self, reverse_items: bool) {
function set_filter (line 422) | pub fn set_filter(&mut self, filter: Option<Filter<T>>) {
function set_scorer (line 436) | pub fn set_scorer(&mut self, scorer: Option<Scorer<T>>) {
function tick (line 445) | pub fn tick(&mut self, timeout: u64) -> Status {
function tick_inner (line 467) | fn tick_inner(&mut self, timeout: u64, canceled: bool, status: pattern::...
method drop (line 513) | fn drop(&mut self) {
FILE: crates/atuin-nucleo/src/par_sort.rs
type CopyOnDrop (line 40) | struct CopyOnDrop<T> {
method drop (line 46) | fn drop(&mut self) {
function shift_head (line 57) | fn shift_head<T, F>(v: &mut [T], is_less: &F)
function shift_tail (line 106) | fn shift_tail<T, F>(v: &mut [T], is_less: &F)
function partial_insertion_sort (line 158) | fn partial_insertion_sort<T, F>(v: &mut [T], is_less: &F) -> bool
function insertion_sort (line 204) | fn insertion_sort<T, F>(v: &mut [T], is_less: &F)
function heapsort (line 215) | fn heapsort<T, F>(v: &mut [T], is_less: &F)
function partition_in_blocks (line 265) | fn partition_in_blocks<T, F>(v: &mut [T], pivot: &T, is_less: &F) -> usize
function partition (line 526) | fn partition<T, F>(v: &mut [T], pivot: usize, is_less: &F) -> (usize, bool)
function partition_equal (line 587) | fn partition_equal<T, F>(v: &mut [T], pivot: usize, is_less: &F) -> usize
function break_patterns (line 648) | fn break_patterns<T>(v: &mut [T]) {
function choose_pivot (line 693) | fn choose_pivot<T, F>(v: &mut [T], is_less: &F) -> (usize, bool)
function recurse (line 769) | fn recurse<'a, T, F>(
function par_quicksort (line 878) | pub(crate) fn par_quicksort<T, F>(v: &mut [T], is_less: F, canceled: &At...
FILE: crates/atuin-nucleo/src/pattern.rs
type Status (line 8) | pub(crate) enum Status {
type MultiPattern (line 16) | pub struct MultiPattern {
method new (line 34) | pub fn new(columns: usize) -> Self {
method reparse (line 44) | pub fn reparse(
method column_pattern (line 70) | pub fn column_pattern(&self, column: usize) -> &Pattern {
method status (line 74) | pub(crate) fn status(&self) -> Status {
method reset_status (line 82) | pub(crate) fn reset_status(&mut self) {
method score (line 88) | pub fn score(&self, haystack: &[Utf32String], matcher: &mut Matcher) -...
method is_empty (line 97) | pub fn is_empty(&self) -> bool {
method clone (line 21) | fn clone(&self) -> Self {
method clone_from (line 27) | fn clone_from(&mut self, source: &Self) {
FILE: crates/atuin-nucleo/src/pattern/tests.rs
function append (line 6) | fn append() {
FILE: crates/atuin-nucleo/src/tests.rs
function active_injector_count (line 8) | fn active_injector_count() {
type TestItem (line 30) | struct TestItem {
function filter_excludes_items (line 37) | fn filter_excludes_items() {
function scorer_affects_sort_order (line 102) | fn scorer_affects_sort_order() {
function filter_and_scorer_combined (line 168) | fn filter_and_scorer_combined() {
function scorer_combines_with_fuzzy_score (line 222) | fn scorer_combines_with_fuzzy_score() {
FILE: crates/atuin-nucleo/src/worker.rs
type Matchers (line 14) | struct Matchers(Box<[UnsafeCell<atuin_nucleo_matcher::Matcher>]>);
method get (line 19) | unsafe fn get(&self) -> &mut atuin_nucleo_matcher::Matcher {
type Worker (line 27) | pub(crate) struct Worker<T: Sync + Send + 'static> {
function item_count (line 46) | pub(crate) fn item_count(&self) -> u32 {
function update_config (line 49) | pub(crate) fn update_config(&mut self, config: Config) {
function sort_results (line 54) | pub(crate) fn sort_results(&mut self, sort_results: bool) {
function reverse_items (line 57) | pub(crate) fn reverse_items(&mut self, reverse_items: bool) {
function set_filter (line 61) | pub(crate) fn set_filter(&mut self, filter: Option<Filter<T>>) {
function set_scorer (line 65) | pub(crate) fn set_scorer(&mut self, scorer: Option<Scorer<T>>) {
function new (line 69) | pub(crate) fn new(
function process_new_items (line 106) | unsafe fn process_new_items(&mut self, unmatched: &AtomicU32) {
function remove_in_flight_matches (line 188) | fn remove_in_flight_matches(&mut self) {
function process_new_items_trivial (line 200) | unsafe fn process_new_items_trivial(&mut self) {
function run (line 228) | pub(crate) unsafe fn run(&mut self, pattern_status: pattern::Status, cle...
function sort_matches (line 310) | unsafe fn sort_matches(&mut self) -> bool {
function reset_matches (line 373) | fn reset_matches(&mut self) {
FILE: crates/atuin-scripts/migrations/20250326160051_create_scripts.up.sql
type scripts (line 2) | CREATE TABLE scripts (
type script_tags (line 11) | CREATE TABLE script_tags (
type idx_script_tags (line 17) | CREATE UNIQUE INDEX idx_script_tags ON script_tags (script_id, tag)
FILE: crates/atuin-scripts/migrations/20250402170430_unique_names.up.sql
type name_uniq_idx (line 2) | create unique index name_uniq_idx ON scripts(name)
FILE: crates/atuin-scripts/src/database.rs
type Database (line 18) | pub struct Database {
method new (line 23) | pub async fn new(path: impl AsRef<Path>, timeout: f64) -> Result<Self> {
method sqlite_version (line 57) | pub async fn sqlite_version(&self) -> Result<String> {
method setup_db (line 63) | async fn setup_db(pool: &SqlitePool) -> Result<()> {
method save_raw (line 71) | async fn save_raw(tx: &mut sqlx::Transaction<'_, sqlx::Sqlite>, s: &Sc...
method save (line 98) | pub async fn save(&self, s: &Script) -> Result<()> {
method save_bulk (line 107) | pub async fn save_bulk(&self, s: &[Script]) -> Result<()> {
method query_script (line 121) | fn query_script(row: SqliteRow) -> Script {
method query_script_tags (line 140) | fn query_script_tags(row: SqliteRow) -> String {
method load (line 145) | async fn load(&self, id: &str) -> Result<Option<Script>> {
method list (line 169) | pub async fn list(&self) -> Result<Vec<Script>> {
method clear (line 191) | pub async fn clear(&self) -> Result<()> {
method delete (line 204) | pub async fn delete(&self, id: &str) -> Result<()> {
method update (line 221) | pub async fn update(&self, s: &Script) -> Result<()> {
method get_by_name (line 259) | pub async fn get_by_name(&self, name: &str) -> Result<Option<Script>> {
function test_list (line 288) | async fn test_list() {
function test_save_load (line 308) | async fn test_save_load() {
function test_save_bulk (line 326) | async fn test_save_bulk() {
function test_delete (line 353) | async fn test_delete() {
FILE: crates/atuin-scripts/src/execution.rs
function build_executable_script (line 12) | pub fn build_executable_script(script: String, shebang: String) -> String {
type ScriptSession (line 24) | pub struct ScriptSession {
method send_input (line 33) | pub async fn send_input(&self, input: String) -> Result<(), mpsc::erro...
method wait_for_exit (line 38) | pub async fn wait_for_exit(&mut self) -> Option<i32> {
function setup_template (line 43) | fn setup_template(script: &Script) -> Result<minijinja::Environment<'_>> {
function template_script (line 52) | pub fn template_script(
function template_variables (line 64) | pub fn template_variables(script: &Script) -> Result<HashSet<String>> {
function execute_script_interactive (line 72) | pub async fn execute_script_interactive(
FILE: crates/atuin-scripts/src/store.rs
type ScriptStore (line 15) | pub struct ScriptStore {
method new (line 22) | pub fn new(store: SqliteStore, host_id: HostId, encryption_key: [u8; 3...
method push_record (line 30) | async fn push_record(&self, record: ScriptRecord) -> Result<(RecordId,...
method create (line 55) | pub async fn create(&self, script: Script) -> Result<()> {
method update (line 61) | pub async fn update(&self, script: Script) -> Result<()> {
method delete (line 67) | pub async fn delete(&self, script_id: uuid::Uuid) -> Result<()> {
method scripts (line 73) | pub async fn scripts(&self) -> Result<Vec<ScriptRecord>> {
method build (line 93) | pub async fn build(&self, database: Database) -> Result<()> {
FILE: crates/atuin-scripts/src/store/record.rs
type ScriptRecord (line 10) | pub enum ScriptRecord {
method serialize (line 17) | pub fn serialize(&self) -> Result<DecryptedData> {
method deserialize (line 49) | pub fn deserialize(data: &DecryptedData, version: &str) -> Result<Self> {
function test_serialize_create (line 99) | fn test_serialize_create() {
function test_serialize_delete (line 125) | fn test_serialize_delete() {
function test_serialize_update (line 142) | fn test_serialize_update() {
function test_serialize_deserialize_create (line 169) | fn test_serialize_deserialize_create() {
function test_serialize_deserialize_delete (line 187) | fn test_serialize_deserialize_delete() {
function test_serialize_deserialize_update (line 199) | fn test_serialize_deserialize_update() {
FILE: crates/atuin-scripts/src/store/script.rs
constant SCRIPT_VERSION (line 11) | pub const SCRIPT_VERSION: &str = "v0";
constant SCRIPT_TAG (line 12) | pub const SCRIPT_TAG: &str = "script";
constant SCRIPT_LEN (line 13) | pub const SCRIPT_LEN: usize = 20000;
type Script (line 17) | pub struct Script {
method serialize (line 42) | pub fn serialize(&self) -> Result<DecryptedData> {
method deserialize (line 65) | pub fn deserialize(bytes: &[u8]) -> Result<Self> {
function test_serialize (line 112) | fn test_serialize() {
function test_serialize_deserialize (line 135) | fn test_serialize_deserialize() {
FILE: crates/atuin-server-database/src/calendar.rs
type TimePeriod (line 6) | pub enum TimePeriod {
type TimePeriodInfo (line 13) | pub struct TimePeriodInfo {
FILE: crates/atuin-server-database/src/lib.rs
type DbError (line 23) | pub enum DbError {
method from (line 35) | fn from(value: T) -> Self {
method fmt (line 29) | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
type DbResult (line 42) | pub type DbResult<T> = Result<T, DbError>;
type DbType (line 45) | pub enum DbType {
type DbSettings (line 52) | pub struct DbSettings {
method db_type (line 59) | pub fn db_type(&self) -> DbType {
function redact_db_uri (line 70) | fn redact_db_uri(uri: &str) -> String {
method fmt (line 81) | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
type Database (line 99) | pub trait Database: Sized + Clone + Send + Sync + 'static {
method new (line 100) | async fn new(settings: &DbSettings) -> DbResult<Self>;
method get_session (line 102) | async fn get_session(&self, token: &str) -> DbResult<Session>;
method get_session_user (line 103) | async fn get_session_user(&self, token: &str) -> DbResult<User>;
method add_session (line 104) | async fn add_session(&self, session: &NewSession) -> DbResult<()>;
method get_user (line 106) | async fn get_user(&self, username: &str) -> DbResult<User>;
method get_user_session (line 107) | async fn get_user_session(&self, u: &User) -> DbResult<Session>;
method add_user (line 108) | async fn add_user(&self, user: &NewUser) -> DbResult<i64>;
method update_user_password (line 110) | async fn update_user_password(&self, u: &User) -> DbResult<()>;
method count_history (line 112) | async fn count_history(&self, user: &User) -> DbResult<i64>;
method count_history_cached (line 113) | async fn count_history_cached(&self, user: &User) -> DbResult<i64>;
method delete_user (line 115) | async fn delete_user(&self, u: &User) -> DbResult<()>;
method delete_history (line 116) | async fn delete_history(&self, user: &User, id: String) -> DbResult<()>;
method deleted_history (line 117) | async fn deleted_history(&self, user: &User) -> DbResult<Vec<String>>;
method delete_store (line 118) | async fn delete_store(&self, user: &User) -> DbResult<()>;
method add_records (line 120) | async fn add_records(&self, user: &User, record: &[Record<EncryptedDat...
method next_records (line 121) | async fn next_records(
method status (line 131) | async fn status(&self, user: &User) -> DbResult<RecordStatus>;
method count_history_range (line 133) | async fn count_history_range(&self, user: &User, range: Range<OffsetDa...
method list_history (line 136) | async fn list_history(
method add_history (line 145) | async fn add_history(&self, history: &[NewHistory]) -> DbResult<()>;
method oldest_history (line 147) | async fn oldest_history(&self, user: &User) -> DbResult<History>;
method calendar (line 150) | async fn calendar(
FILE: crates/atuin-server-database/src/models.rs
type History (line 3) | pub struct History {
type NewHistory (line 18) | pub struct NewHistory {
type User (line 30) | pub struct User {
type Session (line 37) | pub struct Session {
type NewUser (line 43) | pub struct NewUser {
type NewSession (line 49) | pub struct NewSession {
FILE: crates/atuin-server-postgres/build.rs
function main (line 2) | fn main() {
FILE: crates/atuin-server-postgres/migrations/20210425153745_create_history.sql
type history (line 1) | create table history (
FILE: crates/atuin-server-postgres/migrations/20210425153757_create_users.sql
type users (line 1) | create table users (
type email_unique_idx (line 9) | CREATE UNIQUE INDEX email_unique_idx on users (LOWER(email))
type username_unique_idx (line 10) | CREATE UNIQUE INDEX username_unique_idx on users (LOWER(username))
FILE: crates/atuin-server-postgres/migrations/20210425153800_create_sessions.sql
type sessions (line 2) | create table sessions (
FILE: crates/atuin-server-postgres/migrations/20220419082412_add_count_trigger.sql
type total_history_count_user (line 9) | create table total_history_count_user(
function user_history_count (line 15) | create or replace function user_history_count()
FILE: crates/atuin-server-postgres/migrations/20220421073605_fix_count_trigger_delete.sql
function user_history_count (line 4) | create or replace function user_history_count()
FILE: crates/atuin-server-postgres/migrations/20220505082442_create-events.sql
type events (line 3) | create table events (
FILE: crates/atuin-server-postgres/migrations/20230315224203_create-deleted.sql
type history_deleted_index (line 5) | create index if not exists history_deleted_index on history(client_id, u...
FILE: crates/atuin-server-postgres/migrations/20230515221038_trigger-delete-only.sql
function user_history_count (line 5) | create or replace function user_history_count()
FILE: crates/atuin-server-postgres/migrations/20230623070418_records.sql
type records (line 2) | create table records (
FILE: crates/atuin-server-postgres/migrations/20231202170508_create-store.sql
type store (line 2) | create table store (
FILE: crates/atuin-server-postgres/migrations/20231203124112_create-store-idx.sql
type record_uniq (line 2) | create unique index record_uniq ON store(user_id, host, tag, idx)
FILE: crates/atuin-server-postgres/migrations/20240614104159_idx-cache.sql
type store_idx_cache (line 1) | create table store_idx_cache(
FILE: crates/atuin-server-postgres/migrations/20240621110731_user-verified.sql
type user_verification_token (line 3) | create table user_verification_token(
FILE: crates/atuin-server-postgres/migrations/20240702094825_idx_cache_index.sql
type store_idx_cache_uniq (line 1) | create unique index store_idx_cache_uniq on store_idx_cache(user_id, hos...
FILE: crates/atuin-server-postgres/src/lib.rs
constant MIN_PG_VERSION (line 21) | const MIN_PG_VERSION: u32 = 14;
type Postgres (line 24) | pub struct Postgres {
method read_pool (line 33) | fn read_pool(&self) -> &sqlx::Pool<sqlx::postgres::Postgres> {
function fix_error (line 38) | fn fix_error(error: sqlx::Error) -> DbError {
method new (line 47) | async fn new(settings: &DbSettings) -> DbResult<Self> {
method get_session (line 112) | async fn get_session(&self, token: &str) -> DbResult<Session> {
method get_user (line 122) | async fn get_user(&self, username: &str) -> DbResult<User> {
method get_session_user (line 132) | async fn get_session_user(&self, token: &str) -> DbResult<User> {
method count_history (line 147) | async fn count_history(&self, user: &User) -> DbResult<i64> {
method count_history_cached (line 165) | async fn count_history_cached(&self, user: &User) -> DbResult<i64> {
method delete_store (line 178) | async fn delete_store(&self, user: &User) -> DbResult<()> {
method delete_history (line 204) | async fn delete_history(&self, user: &User, id: String) -> DbResult<()> {
method deleted_history (line 223) | async fn deleted_history(&self, user: &User) -> DbResult<Vec<String>> {
method count_history_range (line 247) | async fn count_history_range(
method list_history (line 269) | async fn list_history(
method add_history (line 301) | async fn add_history(&self, history: &[NewHistory]) -> DbResult<()> {
method delete_user (line 332) | async fn delete_user(&self, u: &User) -> DbResult<()> {
method update_user_password (line 367) | async fn update_user_password(&self, user: &User) -> DbResult<()> {
method add_user (line 383) | async fn add_user(&self, user: &NewUser) -> DbResult<i64> {
method add_session (line 405) | async fn add_session(&self, session: &NewSession) -> DbResult<()> {
method get_user_session (line 423) | async fn get_user_session(&self, u: &User) -> DbResult<Session> {
method oldest_history (line 433) | async fn oldest_history(&self, user: &User) -> DbResult<History> {
method add_records (line 448) | async fn add_records(&self, user: &User, records: &[Record<EncryptedData...
method next_records (line 521) | async fn next_records(
method status (line 572) | async fn status(&self, user: &User) -> DbResult<RecordStatus> {
function into_utc (line 614) | fn into_utc(x: OffsetDateTime) -> PrimitiveDateTime {
function utc (line 626) | fn utc() {
FILE: crates/atuin-server-postgres/src/wrappers.rs
type DbUser (line 7) | pub struct DbUser(pub User);
method from_row (line 13) | fn from_row(row: &'a PgRow) -> Result<Self> {
type DbSession (line 8) | pub struct DbSession(pub Session);
method from_row (line 24) | fn from_row(row: &'a PgRow) -> ::sqlx::Result<Self> {
type DbHistory (line 9) | pub struct DbHistory(pub History);
method from_row (line 34) | fn from_row(row: &'a PgRow) -> ::sqlx::Result<Self> {
type DbRecord (line 10) | pub struct DbRecord(pub Record<EncryptedData>);
method from_row (line 52) | fn from_row(row: &'a PgRow) -> ::sqlx::Result<Self> {
function from (line 74) | fn from(other: DbRecord) -> Record<EncryptedData> {
FILE: crates/atuin-server-sqlite/build.rs
function main (line 2) | fn main() {
FILE: crates/atuin-server-sqlite/migrations/20231203124112_create-store.sql
type store (line 1) | create table store (
type record_uniq (line 16) | create unique index record_uniq ON store(user_id, host, tag, idx)
FILE: crates/atuin-server-sqlite/migrations/20240108124830_create-history.sql
type history (line 1) | create table history (
type history_deleted_index (line 14) | create unique index history_deleted_index on history(client_id, user_id,...
FILE: crates/atuin-server-sqlite/migrations/20240108124831_create-sessions.sql
type sessions (line 1) | create table sessions (
FILE: crates/atuin-server-sqlite/migrations/20240621110730_create-users.sql
type users (line 1) | create table users (
type email_unique_idx (line 11) | CREATE UNIQUE INDEX email_unique_idx on users (LOWER(email))
type username_unique_idx (line 12) | CREATE UNIQUE INDEX username_unique_idx on users (LOWER(username))
FILE: crates/atuin-server-sqlite/migrations/20240621110731_create-user-verification-token.sql
type user_verification_token (line 1) | create table user_verification_token(
FILE: crates/atuin-server-sqlite/migrations/20240702094825_create-store-idx-cache.sql
type store_idx_cache (line 1) | create table store_idx_cache(
type store_idx_cache_uniq (line 10) | create unique index store_idx_cache_uniq on store_idx_cache(user_id, hos...
FILE: crates/atuin-server-sqlite/src/lib.rs
type Sqlite (line 22) | pub struct Sqlite {
function fix_error (line 26) | fn fix_error(error: sqlx::Error) -> DbError {
method new (line 35) | async fn new(settings: &DbSettings) -> DbResult<Self> {
method get_session (line 55) | async fn get_session(&self, token: &str) -> DbResult<Session> {
method get_session_user (line 65) | async fn get_session_user(&self, token: &str) -> DbResult<User> {
method add_session (line 80) | async fn add_session(&self, session: &NewSession) -> DbResult<()> {
method get_user (line 98) | async fn get_user(&self, username: &str) -> DbResult<User> {
method get_user_session (line 108) | async fn get_user_session(&self, u: &User) -> DbResult<Session> {
method add_user (line 118) | async fn add_user(&self, user: &NewUser) -> DbResult<i64> {
method update_user_password (line 140) | async fn update_user_password(&self, user: &User) -> DbResult<()> {
method count_history (line 156) | async fn count_history(&self, user: &User) -> DbResult<i64> {
method count_history_cached (line 174) | async fn count_history_cached(&self, _user: &User) -> DbResult<i64> {
method delete_user (line 179) | async fn delete_user(&self, u: &User) -> DbResult<()> {
method delete_history (line 201) | async fn delete_history(&self, user: &User, id: String) -> DbResult<()> {
method deleted_history (line 220) | async fn deleted_history(&self, user: &User) -> DbResult<Vec<String>> {
method delete_store (line 240) | async fn delete_store(&self, user: &User) -> DbResult<()> {
method add_records (line 254) | async fn add_records(&self, user: &User, records: &[Record<EncryptedData...
method next_records (line 288) | async fn next_records(
method status (line 339) | async fn status(&self, user: &User) -> DbResult<RecordStatus> {
method count_history_range (line 359) | async fn count_history_range(
method list_history (line 381) | async fn list_history(
method add_history (line 413) | async fn add_history(&self, history: &[NewHistory]) -> DbResult<()> {
method oldest_history (line 444) | async fn oldest_history(&self, user: &User) -> DbResult<History> {
function into_utc (line 459) | fn into_utc(x: OffsetDateTime) -> PrimitiveDateTime {
FILE: crates/atuin-server-sqlite/src/wrappers.rs
type DbUser (line 6) | pub struct DbUser(pub User);
method from_row (line 12) | fn from_row(row: &'a SqliteRow) -> Result<Self> {
type DbSession (line 7) | pub struct DbSession(pub Session);
method from_row (line 23) | fn from_row(row: &'a SqliteRow) -> ::sqlx::Result<Self> {
type DbHistory (line 8) | pub struct DbHistory(pub History);
method from_row (line 33) | fn from_row(row: &'a SqliteRow) -> ::sqlx::Result<Self> {
type DbRecord (line 9) | pub struct DbRecord(pub Record<EncryptedData>);
method from_row (line 47) | fn from_row(row: &'a SqliteRow) -> ::sqlx::Result<Self> {
function from (line 69) | fn from(other: DbRecord) -> Record<EncryptedData> {
FILE: crates/atuin-server/src/bin/main.rs
type Cmd (line 21) | enum Cmd {
function main (line 38) | async fn main() -> Result<()> {
FILE: crates/atuin-server/src/handlers/health.rs
type HealthResponse (line 6) | pub struct HealthResponse {
function health_check (line 10) | pub async fn health_check() -> impl IntoResponse {
FILE: crates/atuin-server/src/handlers/history.rs
function count (line 26) | pub async fn count<DB: Database>(
function list (line 46) | pub async fn list<DB: Database>(
function delete (line 104) | pub async fn delete<DB: Database>(
function add (line 126) | pub async fn add<DB: Database>(
type CalendarQuery (line 177) | pub struct CalendarQuery {
function zero (line 190) | pub fn zero() -> i32 {
function one (line 194) | pub fn one() -> u8 {
function utc (line 198) | pub fn utc() -> UtcOffset {
function calendar (line 204) | pub async fn calendar<DB: Database>(
FILE: crates/atuin-server/src/handlers/mod.rs
constant VERSION (line 14) | const VERSION: &str = env!("CARGO_PKG_VERSION");
function index (line 16) | pub async fn index<DB: Database>(state: State<AppState<DB>>) -> Json<Ind...
method into_response (line 32) | fn into_response(self) -> axum::response::Response {
type ErrorResponseStatus (line 37) | pub struct ErrorResponseStatus<'a> {
type RespExt (line 42) | pub trait RespExt<'a> {
method with_status (line 43) | fn with_status(self, status: http::StatusCode) -> ErrorResponseStatus<...
method reply (line 44) | fn reply(reason: &'a str) -> Self;
function with_status (line 48) | fn with_status(self, status: http::StatusCode) -> ErrorResponseStatus<'a> {
function reply (line 55) | fn reply(reason: &'a str) -> ErrorResponse<'a> {
FILE: crates/atuin-server/src/handlers/record.rs
function post (line 11) | pub async fn post(UserAuth(user): UserAuth) -> Result<(), ErrorResponseS...
function index (line 27) | pub async fn index(UserAuth(user): UserAuth) -> axum::response::Response {
function next (line 36) | pub async fn next(
FILE: crates/atuin-server/src/handlers/status.rs
constant VERSION (line 10) | const VERSION: &str = env!("CARGO_PKG_VERSION");
function status (line 13) | pub async fn status<DB: Database>(
FILE: crates/atuin-server/src/handlers/user.rs
function verify_str (line 32) | pub fn verify_str(hash: &str, password: &str) -> bool {
function send_register_hook (line 42) | async fn send_register_hook(url: &str, username: String, registered: Str...
function get (line 66) | pub async fn get<DB: Database>(
function register (line 90) | pub async fn register<DB: Database>(
function delete (line 163) | pub async fn delete<DB: Database>(
function change_password (line 183) | pub async fn change_password<DB: Database>(
function login (line 213) | pub async fn login<DB: Database>(
function hash_secret (line 260) | fn hash_secret(password: &str) -> String {
FILE: crates/atuin-server/src/handlers/v0/me.rs
function get (line 10) | pub async fn get(
FILE: crates/atuin-server/src/handlers/v0/record.rs
function post (line 15) | pub async fn post<DB: Database>(
function index (line 54) | pub async fn index<DB: Database>(
type NextParams (line 79) | pub struct NextParams {
function next (line 87) | pub async fn next<DB: Database>(
FILE: crates/atuin-server/src/handlers/v0/store.rs
type DeleteParams (line 13) | pub struct DeleteParams {}
function delete (line 16) | pub async fn delete<DB: Database>(
FILE: crates/atuin-server/src/lib.rs
function shutdown_signal (line 24) | async fn shutdown_signal() {
function shutdown_signal (line 38) | async fn shutdown_signal() {
function launch (line 46) | pub async fn launch<Db: Database>(settings: Settings, addr: SocketAddr) ...
function launch_with_tcp_listener (line 57) | pub async fn launch_with_tcp_listener<Db: Database>(
function launch_metrics_server (line 73) | pub async fn launch_metrics_server(host: String, port: u16) -> Result<()> {
function make_router (line 92) | async fn make_router<Db: Database>(settings: Settings) -> Result<Router,...
FILE: crates/atuin-server/src/metrics.rs
function setup_metrics_recorder (line 10) | pub fn setup_metrics_recorder() -> PrometheusHandle {
function track_metrics (line 28) | pub async fn track_metrics(req: Request, next: Next) -> impl IntoResponse {
FILE: crates/atuin-server/src/router.rs
type UserAuth (line 22) | pub struct UserAuth(pub User);
type Rejection (line 28) | type Rejection = ErrorResponseStatus<'static>;
method from_request_parts (line 30) | async fn from_request_parts(
function teapot (line 75) | async fn teapot() -> impl IntoResponse {
function clacks_overhead (line 81) | async fn clacks_overhead(request: Request, next: Next) -> Response {
function semver (line 94) | async fn semver(request: Request, next: Next) -> Response {
type AppState (line 104) | pub struct AppState<DB: Database> {
function router (line 109) | pub fn router<DB: Database>(database: DB, settings: Settings) -> Router {
FILE: crates/atuin-server/src/settings.rs
type Metrics (line 12) | pub struct Metrics {
method default (line 20) | fn default() -> Self {
type Settings (line 30) | pub struct Settings {
method new (line 58) | pub fn new() -> Result<Self> {
function example_config (line 111) | pub fn example_config() -> &'static str {
FILE: crates/atuin-server/src/utils.rs
function client_version_min (line 4) | pub fn client_version_min(user_agent: &str, req: &str) -> Result<bool> {
FILE: crates/atuin/build.rs
function main (line 2) | fn main() {
FILE: crates/atuin/src/command/client.rs
function cleanup_old_logs (line 15) | fn cleanup_old_logs(log_dir: &Path, prefix: &str, retention_days: u64) {
type Cmd (line 69) | pub enum Cmd {
method run (line 143) | pub fn run(self) -> Result<()> {
method run_inner (line 168) | async fn run_inner(
FILE: crates/atuin/src/command/client/account.rs
type Cmd (line 15) | pub struct Cmd {
method run (line 42) | pub async fn run(self, settings: Settings, store: SqliteStore) -> Resu...
type Commands (line 21) | pub enum Commands {
FILE: crates/atuin/src/command/client/account/change_password.rs
type Cmd (line 11) | pub struct Cmd {
method run (line 24) | pub async fn run(&self, settings: &Settings) -> Result<()> {
FILE: crates/atuin/src/command/client/account/delete.rs
type Cmd (line 11) | pub struct Cmd {
method run (line 21) | pub async fn run(&self, settings: &Settings) -> Result<()> {
FILE: crates/atuin/src/command/client/account/link.rs
function run (line 5) | pub async fn run(settings: &Settings) -> Result<()> {
FILE: crates/atuin/src/command/client/account/login.rs
type Cmd (line 17) | pub struct Cmd {
method run (line 43) | pub async fn run(&self, settings: &Settings, store: &SqliteStore) -> R...
method run_hub_login (line 63) | async fn run_hub_login(&self, settings: &Settings, store: &SqliteStore...
method run_legacy_login (line 116) | async fn run_legacy_login(&self, settings: &Settings, store: &SqliteSt...
method ensure_hub_session (line 139) | async fn ensure_hub_session(&self, _settings: &Settings, hub_address: ...
method prompt_and_store_key (line 160) | async fn prompt_and_store_key(&self, settings: &Settings, store: &Sqli...
function get_input (line 36) | fn get_input() -> Result<String> {
function or_user_input (line 254) | pub(super) fn or_user_input(value: Option<String>, name: &'static str) -...
function read_user_password (line 258) | pub(super) fn read_user_password() -> String {
function read_user_input (line 263) | fn read_user_input(name: &'static str) -> String {
function mnemonic_round_trip (line 273) | fn mnemonic_round_trip() {
FILE: crates/atuin/src/command/client/account/logout.rs
function run (line 3) | pub async fn run() -> Result<()> {
FILE: crates/atuin/src/command/client/account/register.rs
type Cmd (line 12) | pub struct Cmd {
method run (line 24) | pub async fn run(&self, settings: &Settings, store: &SqliteStore) -> R...
FILE: crates/atuin/src/command/client/daemon.rs
type Cmd (line 21) | pub struct Cmd {
method should_daemonize (line 65) | pub fn should_daemonize(&self) -> bool {
method show_logs (line 74) | pub fn show_logs(&self) -> bool {
method run (line 82) | pub async fn run(
type SubCmd (line 36) | pub enum SubCmd {
constant DAEMON_VERSION (line 101) | const DAEMON_VERSION: &str = env!("CARGO_PKG_VERSION");
constant DAEMON_PROTOCOL_VERSION (line 102) | const DAEMON_PROTOCOL_VERSION: u32 = 1;
constant STARTUP_POLL (line 103) | const STARTUP_POLL: Duration = Duration::from_millis(40);
constant LOCK_POLL (line 104) | const LOCK_POLL: Duration = Duration::from_millis(20);
constant LEGACY_DAEMON_RESTART_MESSAGE (line 105) | const LEGACY_DAEMON_RESTART_MESSAGE: &str = "legacy daemon detected; res...
type PidfileGuard (line 107) | struct PidfileGuard {
method acquire (line 112) | fn acquire(path: &Path) -> Result<Self> {
method drop (line 133) | fn drop(&mut self) {
type Probe (line 138) | enum Probe {
function daemon_matches_expected (line 144) | fn daemon_matches_expected(version: &str, protocol: u32) -> bool {
function daemon_mismatch_message (line 148) | fn daemon_mismatch_message(version: &str, protocol: u32) -> String {
function is_legacy_daemon_error (line 156) | fn is_legacy_daemon_error(err: &eyre::Report) -> bool {
function should_retry_after_error (line 160) | fn should_retry_after_error(err: &eyre::Report) -> bool {
function daemon_startup_lock_path (line 169) | fn daemon_startup_lock_path(pidfile_path: &Path) -> PathBuf {
function open_lock_file (line 175) | fn open_lock_file(path: &Path) -> Result<File> {
function wait_for_lock (line 190) | async fn wait_for_lock(path: &Path, timeout: Duration) -> Result<File> {
function wait_for_pidfile_available (line 211) | async fn wait_for_pidfile_available(path: &Path, timeout: Duration) -> R...
function connect_client (line 218) | async fn connect_client(settings: &Settings) -> Result<HistoryClient> {
function probe (line 228) | async fn probe(settings: &Settings) -> Probe {
function request_shutdown (line 246) | async fn request_shutdown(settings: &Settings) {
function spawn_daemon_process (line 252) | fn spawn_daemon_process() -> Result<()> {
function startup_timeout (line 270) | fn startup_timeout(settings: &Settings) -> Duration {
function remove_stale_socket_if_present (line 275) | fn remove_stale_socket_if_present(settings: &Settings) -> Result<()> {
function wait_until_ready (line 304) | async fn wait_until_ready(settings: &Settings, timeout: Duration) -> Res...
function ensure_autostart_supported (line 333) | fn ensure_autostart_supported(settings: &Settings) -> Result<()> {
function restart_daemon (line 346) | async fn restart_daemon(settings: &Settings) -> Result<HistoryClient> {
function ensure_reply_compatible (line 382) | fn ensure_reply_compatible(settings: &Settings, version: &str, protocol:...
function start_history (line 395) | pub async fn start_history(settings: &Settings, history: History) -> Res...
function end_history (line 429) | pub async fn end_history(settings: &Settings, id: String, duration: u64,...
function status_cmd (line 468) | async fn status_cmd(settings: &Settings) -> Result<()> {
function stop_cmd (line 494) | async fn stop_cmd(settings: &Settings) -> Result<()> {
function restart_cmd (line 518) | async fn restart_cmd(settings: &Settings) -> Result<()> {
function daemonize_current_process (line 556) | pub fn daemonize_current_process() -> Result<()> {
function run (line 568) | async fn run(
function force_cleanup (line 587) | fn force_cleanup(settings: &Settings) {
function kill_process (line 624) | fn kill_process(pid: u32) {
function kill_process (line 635) | fn kill_process(pid: u32) {
function test_version_matches (line 649) | fn test_version_matches() {
function test_version_mismatch (line 657) | fn test_version_mismatch() {
function test_mismatch_message_version (line 664) | fn test_mismatch_message_version() {
function test_mismatch_message_protocol (line 672) | fn test_mismatch_message_protocol() {
function test_startup_lock_path (line 678) | fn test_startup_lock_path() {
function test_pidfile_guard_acquire_and_drop (line 685) | fn test_pidfile_guard_acquire_and_drop() {
function test_pidfile_guard_prevents_double_acquire (line 706) | fn test_pidfile_guard_prevents_double_acquire() {
FILE: crates/atuin/src/command/client/default_config.rs
function run (line 3) | pub fn run() {
FILE: crates/atuin/src/command/client/doctor.rs
type ShellInfo (line 15) | struct ShellInfo {
method shellvar_exists (line 36) | fn shellvar_exists(shell: &str, var: &str) -> bool {
method detect_preexec_framework (line 51) | fn detect_preexec_framework(shell: &str) -> Option<String> {
method validate_plugin_blesh (line 76) | fn validate_plugin_blesh(
method plugins (line 89) | pub fn plugins(shell: &str, shell_process: &sysinfo::Process) -> Vec<S...
method new (line 170) | pub fn new() -> Self {
type DiskInfo (line 201) | struct DiskInfo {
type SystemInfo (line 207) | struct SystemInfo {
method new (line 217) | pub fn new() -> Self {
type SyncInfo (line 238) | struct SyncInfo {
method new (line 249) | pub async fn new(settings: &Settings) -> Self {
type SettingPaths (line 262) | struct SettingPaths {
method new (line 269) | pub fn new(settings: &Settings) -> Self {
method verify (line 277) | pub fn verify(&self) {
type AtuinInfo (line 295) | struct AtuinInfo {
method new (line 310) | pub async fn new(settings: &Settings) -> Self {
type DoctorDump (line 338) | struct DoctorDump {
method new (line 345) | pub async fn new(settings: &Settings) -> Self {
function checks (line 354) | fn checks(info: &DoctorDump) {
function run (line 388) | pub async fn run(settings: &Settings) -> Result<()> {
FILE: crates/atuin/src/command/client/dotfiles.rs
type Cmd (line 11) | pub enum Cmd {
method run (line 22) | pub async fn run(self, settings: &Settings, store: SqliteStore) -> Res...
FILE: crates/atuin/src/command/client/dotfiles/alias.rs
type SortBy (line 9) | pub enum SortBy {
type Cmd (line 19) | pub enum Cmd {
method set (line 52) | async fn set(&self, store: &AliasStore, name: String, value: String) -...
method list (line 75) | async fn list(
method clear (line 117) | async fn clear(&self, store: &AliasStore) -> Result<()> {
method delete (line 127) | async fn delete(&self, store: &AliasStore, name: String) -> Result<()> {
method run (line 150) | pub async fn run(&self, settings: &Settings, store: SqliteStore) -> Re...
FILE: crates/atuin/src/command/client/dotfiles/var.rs
type SortBy (line 9) | pub enum SortBy {
type Cmd (line 19) | pub enum Cmd {
method set (line 61) | async fn set(&self, store: VarStore, name: String, value: String, expo...
method list (line 81) | async fn list(
method delete (line 137) | async fn delete(&self, store: VarStore, name: String) -> Result<()> {
method run (line 150) | pub async fn run(&self, settings: &Settings, store: SqliteStore) -> Re...
FILE: crates/atuin/src/command/client/history.rs
type Cmd (line 39) | pub enum Cmd {
method apply_start_metadata (line 368) | fn apply_start_metadata(history: &mut History, author: Option<&str>, i...
method handle_start (line 381) | async fn handle_start(
method handle_daemon_start (line 418) | async fn handle_daemon_start(
method handle_end (line 458) | async fn handle_end(
method handle_daemon_end (line 525) | async fn handle_daemon_end(
method handle_list (line 538) | async fn handle_list(
method handle_prune (line 580) | async fn handle_prune(
method handle_dedup (line 637) | async fn handle_dedup(
method run (line 698) | pub async fn run(self, settings: &Settings) -> Result<()> {
method get_start_command (line 809) | fn get_start_command(&self) -> Option<String> {
method get_start_metadata (line 821) | fn get_start_metadata(&self) -> Option<(Option<&str>, Option<&str>)> {
type ListMode (line 156) | pub enum ListMode {
method from_flags (line 163) | pub const fn from_flags(human: bool, cmd_only: bool) -> Self {
function print_list (line 175) | pub fn print_list(
function check_for_write_errors (line 260) | fn check_for_write_errors(write: Result<(), io::Error>) {
type FmtHistory (line 272) | struct FmtHistory<'a> {
type CmdFormat (line 279) | enum CmdFormat {
method for_output (line 284) | fn for_output<O: IsTerminal>(out: &O) -> Self {
method fmt (line 299) | fn fmt(&self, key: &str, f: &mut fmt::Formatter<'_>) -> Result<(), Forma...
function parse_fmt (line 346) | fn parse_fmt(format: &str) -> ParsedFmt<'_> {
function test_format_string_no_panic (line 834) | fn test_format_string_no_panic() {
function test_valid_formats_still_work (line 844) | fn test_valid_formats_still_work() {
FILE: crates/atuin/src/command/client/import.rs
type Cmd (line 20) | pub enum Cmd {
method run (line 52) | pub async fn run<DB: Database>(&self, db: &DB) -> Result<()> {
constant BATCH_SIZE (line 48) | const BATCH_SIZE: usize = 100;
type HistoryImporter (line 138) | pub struct HistoryImporter<'db, DB: Database> {
function new (line 145) | fn new(db: &'db DB, len: usize) -> Self {
function flush (line 153) | async fn flush(self) -> Result<()> {
method push (line 164) | async fn push(&mut self, hist: History) -> Result<()> {
function import (line 175) | async fn import<I: Importer + Send, DB: Database>(db: &DB) -> Result<()> {
FILE: crates/atuin/src/command/client/info.rs
function run (line 5) | pub fn run(settings: &Settings) {
FILE: crates/atuin/src/command/client/init.rs
type Cmd (line 19) | pub struct Cmd {
method init_nu (line 54) | fn init_nu(&self, _tmux: &Tmux) {
method static_init (line 101) | fn static_init(&self, tmux: &Tmux) {
method dotfiles_init (line 139) | async fn dotfiles_init(&self, settings: &Settings) -> Result<()> {
method run (line 211) | pub async fn run(self, settings: &Settings) -> Result<()> {
type Shell (line 38) | pub enum Shell {
FILE: crates/atuin/src/command/client/init/bash.rs
function print_tmux_config (line 5) | fn print_tmux_config(tmux: &Tmux) {
function init_static (line 14) | pub fn init_static(disable_up_arrow: bool, disable_ctrl_r: bool, disable...
function init (line 35) | pub async fn init(
FILE: crates/atuin/src/command/client/init/fish.rs
function print_tmux_config (line 5) | fn print_tmux_config(tmux: &Tmux) {
function print_bindings (line 14) | fn print_bindings(
function init_static (line 40) | pub fn init_static(disable_up_arrow: bool, disable_ctrl_r: bool, disable...
function init (line 96) | pub async fn init(
FILE: crates/atuin/src/command/client/init/powershell.rs
function init_static (line 4) | pub fn init_static(disable_up_arrow: bool, disable_ctrl_r: bool, _tmux: ...
function init (line 22) | pub async fn init(
function ps_bool (line 40) | fn ps_bool(value: bool) -> &'static str {
FILE: crates/atuin/src/command/client/init/xonsh.rs
function init_static (line 5) | pub fn init_static(disable_up_arrow: bool, disable_ctrl_r: bool, _tmux: ...
function init (line 26) | pub async fn init(
FILE: crates/atuin/src/command/client/init/zsh.rs
function print_tmux_config (line 5) | fn print_tmux_config(tmux: &Tmux) {
function init_static (line 14) | pub fn init_static(disable_up_arrow: bool, disable_ctrl_r: bool, disable...
function init (line 49) | pub async fn init(
FILE: crates/atuin/src/command/client/kv.rs
type Cmd (line 11) | pub enum Cmd {
method run (line 65) | pub async fn run(&self, settings: &Settings, store: &SqliteStore) -> R...
FILE: crates/atuin/src/command/client/scripts.rs
type NewScript (line 21) | pub struct NewScript {
type Run (line 48) | pub struct Run {
type List (line 58) | pub struct List {}
type Get (line 61) | pub struct Get {
type Edit (line 70) | pub struct Edit {
type Delete (line 101) | pub struct Delete {
type Cmd (line 110) | pub enum Cmd {
method open_editor (line 124) | fn open_editor(initial_content: Option<&str>) -> Result<String> {
method execute_script (line 157) | async fn execute_script(script_content: String, shebang: String) -> Re...
method handle_new_script (line 219) | async fn handle_new_script(
method handle_run (line 290) | async fn handle_run(
method handle_list (line 366) | async fn handle_list(
method handle_get (line 394) | async fn handle_get(
method handle_edit (line 450) | async fn handle_edit(
method handle_delete (line 524) | async fn handle_delete(
method run (line 563) | pub async fn run(
FILE: crates/atuin/src/command/client/search.rs
type Cmd (line 32) | pub struct Cmd {
method is_interactive (line 145) | pub fn is_interactive(&self) -> bool {
method run (line 153) | pub async fn run(
function run_non_interactive (line 306) | async fn run_non_interactive(
function search_for_triple_dash (line 346) | fn search_for_triple_dash() {
function search_for_double_dash_value (line 355) | fn search_for_double_dash_value() {
FILE: crates/atuin/src/command/client/search/cursor.rs
type Cursor (line 3) | pub struct Cursor {
method from (line 9) | fn from(source: String) -> Self {
method as_str (line 96) | pub fn as_str(&self) -> &str {
method into_inner (line 100) | pub fn into_inner(self) -> String {
method substring (line 105) | pub fn substring(&self) -> &str {
method char (line 110) | pub fn char(&self) -> Option<char> {
method right (line 114) | pub fn right(&mut self) {
method left (line 125) | pub fn left(&mut self) -> bool {
method next_word (line 138) | pub fn next_word(&mut self, word_chars: &str, word_jump_mode: WordJump...
method prev_word (line 146) | pub fn prev_word(&mut self, word_chars: &str, word_jump_mode: WordJump...
method word_end (line 159) | pub fn word_end(&mut self, word_chars: &str) {
method insert (line 216) | pub fn insert(&mut self, c: char) {
method remove (line 221) | pub fn remove(&mut self) -> Option<char> {
method remove_next_word (line 229) | pub fn remove_next_word(&mut self, word_chars: &str, word_jump_mode: W...
method remove_prev_word (line 238) | pub fn remove_prev_word(&mut self, word_chars: &str, word_jump_mode: W...
method back (line 248) | pub fn back(&mut self) -> Option<char> {
method clear (line 252) | pub fn clear(&mut self) {
method clear_to_start (line 257) | pub fn clear_to_start(&mut self) {
method clear_to_end (line 262) | pub fn clear_to_end(&mut self) {
method end (line 267) | pub fn end(&mut self) {
method start (line 271) | pub fn start(&mut self) {
method position (line 275) | pub fn position(&self) -> usize {
type WordJumper (line 14) | pub struct WordJumper<'a> {
function is_word_boundary (line 20) | fn is_word_boundary(&self, c: char, next_c: char) -> bool {
function emacs_get_next_word_pos (line 27) | fn emacs_get_next_word_pos(&self, source: &str, index: usize) -> usize {
function emacs_get_prev_word_pos (line 36) | fn emacs_get_prev_word_pos(&self, source: &str, index: usize) -> usize {
function subl_get_next_word_pos (line 47) | fn subl_get_next_word_pos(&self, source: &str, index: usize) -> usize {
function subl_get_prev_word_pos (line 62) | fn subl_get_prev_word_pos(&self, source: &str, index: usize) -> usize {
function get_next_word_pos (line 80) | fn get_next_word_pos(&self, source: &str, index: usize) -> usize {
function get_prev_word_pos (line 87) | fn get_prev_word_pos(&self, source: &str, index: usize) -> usize {
function right (line 296) | fn right() {
function left (line 307) | fn left() {
function test_emacs_get_next_word_pos (line 319) | fn test_emacs_get_next_word_pos() {
function test_emacs_get_prev_word_pos (line 329) | fn test_emacs_get_prev_word_pos() {
function test_subl_get_next_word_pos (line 339) | fn test_subl_get_next_word_pos() {
function test_subl_get_prev_word_pos (line 349) | fn test_subl_get_prev_word_pos() {
function pop (line 359) | fn pop() {
function back (line 375) | fn back() {
function insert (line 391) | fn insert() {
FILE: crates/atuin/src/command/client/search/duration.rs
function format_duration_into (line 5) | pub fn format_duration_into(dur: Duration, f: &mut fmt::Formatter<'_>) -...
function format_duration (line 57) | pub fn format_duration(f: Duration) -> String {
FILE: crates/atuin/src/command/client/search/engines.rs
function engine (line 17) | pub fn engine(search_mode: SearchMode, settings: &Settings) -> Box<dyn S...
type SearchState (line 31) | pub struct SearchState {
method rotate_filter_mode (line 39) | pub(crate) fn rotate_filter_mode(&mut self, settings: &Settings, offse...
method filter_mode_available (line 56) | fn filter_mode_available(&self, mode: FilterMode, settings: &Settings)...
type SearchEngine (line 66) | pub trait SearchEngine: Send + Sync + 'static {
method full_query (line 67) | async fn full_query(
method query (line 73) | async fn query(&mut self, state: &SearchState, db: &mut dyn Database) ...
method get_highlight_indices (line 84) | fn get_highlight_indices(&self, command: &str, search_input: &str) -> ...
FILE: crates/atuin/src/command/client/search/engines/daemon.rs
type Search (line 18) | pub struct Search {
method new (line 27) | pub fn new(settings: &Settings) -> Self {
method get_client (line 38) | async fn get_client(&mut self) -> Result<&mut SearchClient> {
method next_query_id (line 51) | fn next_query_id(&mut self) -> u64 {
method contains_regex_pattern (line 58) | fn contains_regex_pattern(query: &str) -> bool {
method fallback_to_db_search (line 63) | async fn fallback_to_db_search(
method hydrate_from_db (line 85) | async fn hydrate_from_db(&self, db: &dyn Database, ids: &[String]) -> ...
method full_query (line 98) | async fn full_query(
method get_highlight_indices (line 188) | fn get_highlight_indices(&self, command: &str, search_input: &str) -> Ve...
FILE: crates/atuin/src/command/client/search/engines/db.rs
type Search (line 16) | pub struct Search(pub SearchMode);
method full_query (line 21) | async fn full_query(
method get_highlight_indices (line 44) | fn get_highlight_indices(&self, command: &str, search_input: &str) -> Ve...
function get_highlight_indices_fulltext (line 62) | pub fn get_highlight_indices_fulltext(command: &str, search_input: &str)...
FILE: crates/atuin/src/command/client/search/engines/skim.rs
type Search (line 15) | pub struct Search {
method new (line 21) | pub fn new() -> Self {
method full_query (line 32) | async fn full_query(
method get_highlight_indices (line 45) | fn get_highlight_indices(&self, command: &str, search_input: &str) -> Ve...
function load_all_history (line 55) | async fn load_all_history(db: &dyn Database) -> Vec<(History, i32)> {
function fuzzy_search (line 61) | async fn fuzzy_search(
function path_dist (line 209) | fn path_dist(a: &Path, b: &Path) -> usize {
FILE: crates/atuin/src/command/client/search/history_list.rs
type HistoryHighlighter (line 22) | pub struct HistoryHighlighter<'a> {
function get_highlight_indices (line 28) | pub fn get_highlight_indices(&self, command: &str) -> Vec<usize> {
type HistoryList (line 34) | pub struct HistoryList<'a> {
type ListState (line 50) | pub struct ListState {
method selected (line 57) | pub fn selected(&self) -> usize {
method max_entries (line 61) | pub fn max_entries(&self) -> usize {
method offset (line 65) | pub fn offset(&self) -> usize {
method select (line 69) | pub fn select(&mut self, index: usize) {
type State (line 75) | type State = ListState;
method render (line 77) | fn render(mut self, area: Rect, buf: &mut Buffer, state: &mut Self::Stat...
function new (line 121) | pub fn new(
function block (line 146) | pub fn block(mut self, block: Block<'a>) -> Self {
function get_items_bounds (line 151) | fn get_items_bounds(&self, selected: usize, offset: usize, height: usize...
type DrawState (line 166) | struct DrawState<'a> {
function render_row (line 188) | fn render_row(&mut self, h: &History) {
function index (line 230) | fn index(&mut self) {
function duration (line 253) | fn duration(&mut self, h: &History, width: u16) {
function time (line 267) | fn time(&mut self, h: &History, width: u16) {
function command (line 286) | fn command(&mut self, h: &History) {
function datetime (line 334) | fn datetime(&mut self, h: &History, width: u16) {
function directory (line 350) | fn directory(&mut self, h: &History, width: u16) {
function host (line 367) | fn host(&mut self, h: &History, width: u16) {
function user (line 384) | fn user(&mut self, h: &History, width: u16) {
function exit_code (line 401) | fn exit_code(&mut self, h: &History, width: u16) {
function draw (line 412) | fn draw(&mut self, s: &str, mut style: Style) {
FILE: crates/atuin/src/command/client/search/inspector.rs
function u64_or_zero (line 24) | fn u64_or_zero(num: i64) -> u64 {
function draw_commands (line 28) | pub fn draw_commands(
function draw_stats_table (line 116) | pub fn draw_stats_table(
function num_to_day (line 159) | fn num_to_day(num: &str) -> String {
function sort_duration_over_time (line 172) | fn sort_duration_over_time(durations: &[(String, i64)]) -> Vec<(String, ...
function draw_stats_charts (line 199) | fn draw_stats_charts(f: &mut Frame<'_>, parent: Rect, stats: &HistorySta...
function draw (line 288) | pub fn draw(
function draw_ultracompact (line 305) | pub fn draw_ultracompact(
function draw_full (line 315) | pub fn draw_full(
function mock_history_stats (line 348) | fn mock_history_stats() -> (History, HistoryStats) {
function test_output_looks_correct_for_ultracompact (line 401) | fn test_output_looks_correct_for_ultracompact() {
FILE: crates/atuin/src/command/client/search/interactive.rs
constant TAB_TITLES (line 55) | const TAB_TITLES: [&str; 2] = ["Search", "Inspect"];
type InputAction (line 57) | pub enum InputAction {
type InspectingState (line 70) | pub struct InspectingState {
method move_to_previous (line 77) | pub fn move_to_previous(&mut self) {
method move_to_next (line 83) | pub fn move_to_next(&mut self) {
method reset (line 89) | pub fn reset(&mut self) {
function to_compactness (line 96) | pub fn to_compactness(f: &Frame, settings: &Settings) -> Compactness {
type State (line 114) | pub struct State {
method query_results (line 152) | async fn query_results(
method handle_input (line 177) | fn handle_input(&mut self, settings: &Settings, input: &Event) -> Inpu...
method handle_mouse_input (line 186) | fn handle_mouse_input(&mut self, input: MouseEvent) -> InputAction {
method handle_paste_input (line 199) | fn handle_paste_input(&mut self, input: &str) -> InputAction {
method cast_cursor_style (line 206) | fn cast_cursor_style(style: CursorStyle) -> SetCursorStyle {
method set_keymap_cursor (line 218) | fn set_keymap_cursor(&mut self, settings: &Settings, keymap_name: &str) {
method initialize_keymap_cursor (line 234) | pub fn initialize_keymap_cursor(&mut self, settings: &Settings) {
method finalize_keymap_cursor (line 243) | pub fn finalize_keymap_cursor(&mut self, settings: &Settings) {
method handle_key_exit (line 252) | fn handle_key_exit(settings: &Settings) -> InputAction {
method mode_keymap (line 260) | fn mode_keymap(&self) -> &super::keybindings::Keymap {
method is_insert_mode (line 273) | fn is_insert_mode(&self) -> bool {
method handle_key_input (line 280) | fn handle_key_input(&mut self, settings: &Settings, input: &KeyEvent) ...
method scroll_down (line 387) | fn scroll_down(&mut self, scroll_len: usize) {
method scroll_up (line 393) | fn scroll_up(&mut self, scroll_len: usize) {
method execute_action (line 410) | pub(crate) fn execute_action(
method calc_preview_height (line 727) | fn calc_preview_height(
method draw (line 802) | fn draw(
method draw_inner (line 822) | fn draw_inner(
method draw_preview (line 1054) | fn draw_preview(
method build_title (line 1082) | fn build_title(&self, theme: &Theme) -> Paragraph<'_> {
method build_help (line 1100) | fn build_help(&self, settings: &Settings, theme: &Theme) -> Paragraph<...
method build_stats (line 1138) | fn build_stats(&self, theme: &Theme) -> Paragraph<'_> {
method build_results_list (line 1148) | fn build_results_list<'a>(
method build_input (line 1192) | fn build_input(&self, style: StyleState, prefix_width: u16) -> Paragra...
method build_preview (line 1227) | fn build_preview(
type Compactness (line 138) | pub enum Compactness {
type StyleState (line 145) | struct StyleState {
type TerminalWriter (line 1267) | enum TerminalWriter {
method write (line 1274) | fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
method flush (line 1282) | fn flush(&mut self) -> std::io::Result<()> {
type SavedScreen (line 1293) | struct SavedScreen {
function fetch_screen_state (line 1314) | fn fetch_screen_state(socket_path: &str) -> Option<SavedScreen> {
function restore_popup_area (line 1365) | fn restore_popup_area(saved: &SavedScreen, popup_rect: Rect, scroll_offs...
type Stdout (line 1403) | struct Stdout {
method new (line 1409) | pub fn new(inline_mode: bool, stdout_is_terminal: bool) -> std::io::Re...
method drop (line 1464) | fn drop(&mut self) {
method write (line 1483) | fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
method flush (line 1487) | fn flush(&mut self) -> std::io::Result<()> {
function compute_popup_placement (line 1500) | fn compute_popup_placement(
function history (line 1533) | pub async fn history(
function set_clipboard (line 1957) | fn set_clipboard(s: String) {
function set_clipboard (line 1968) | fn set_clipboard(_s: String) {}
function calc_preview_height_test (line 1986) | fn calc_preview_height_test() {
function state_scroll_up_underflow (line 2140) | fn state_scroll_up_underflow() {
function test_accept_keybindings (line 2183) | fn test_accept_keybindings() {
function test_vim_gg_multikey_sequence (line 2311) | fn test_vim_gg_multikey_sequence() {
function test_vim_g_key_clears_on_other_input (line 2370) | fn test_vim_g_key_clears_on_other_input() {
function test_vim_big_g_jump_to_bottom (line 2425) | fn test_vim_big_g_jump_to_bottom() {
function test_vim_ctrl_u_d_half_page_scroll (line 2476) | fn test_vim_ctrl_u_d_half_page_scroll() {
function test_vim_ctrl_f_b_full_page_scroll (line 2536) | fn test_vim_ctrl_f_b_full_page_scroll() {
function make_executor_state (line 2600) | fn make_executor_state(results_len: usize, selected: usize) -> State {
function execute_select_next_no_invert (line 2642) | fn execute_select_next_no_invert() {
function execute_select_next_with_invert (line 2654) | fn execute_select_next_with_invert() {
function execute_select_previous_no_invert (line 2667) | fn execute_select_previous_no_invert() {
function execute_vim_enter_normal (line 2679) | fn execute_vim_enter_normal() {
function execute_vim_enter_insert (line 2690) | fn execute_vim_enter_insert() {
function execute_accept_sets_accept_flag (line 2702) | fn execute_accept_sets_accept_flag() {
function execute_return_selection_does_not_set_accept (line 2714) | fn execute_return_selection_does_not_set_accept() {
function execute_accept_nth (line 2725) | fn execute_accept_nth() {
function execute_scroll_to_top_no_invert (line 2735) | fn execute_scroll_to_top_no_invert() {
function execute_scroll_to_top_with_invert (line 2747) | fn execute_scroll_to_top_with_invert() {
function execute_scroll_to_bottom_no_invert (line 2760) | fn execute_scroll_to_bottom_no_invert() {
function execute_toggle_tab (line 2772) | fn execute_toggle_tab() {
function execute_enter_prefix_mode (line 2785) | fn execute_enter_prefix_mode() {
function execute_exit_returns_based_on_exit_mode (line 2796) | fn execute_exit_returns_based_on_exit_mode() {
function execute_return_original (line 2813) | fn execute_return_original() {
function execute_copy (line 2823) | fn execute_copy() {
function execute_delete (line 2833) | fn execute_delete() {
function execute_switch_context (line 2843) | fn execute_switch_context() {
function execute_clear_context (line 2853) | fn execute_clear_context() {
function execute_noop (line 2863) | fn execute_noop() {
function execute_accept_in_inspector_tab (line 2874) | fn execute_accept_in_inspector_tab() {
function execute_cycle_search_mode (line 2885) | fn execute_cycle_search_mode() {
function execute_vim_search_insert (line 2898) | fn execute_vim_search_insert() {
function execute_cursor_movement (line 2914) | fn execute_cursor_movement() {
function execute_editing (line 2946) | fn execute_editing() {
function keymap_config_return_query (line 2969) | fn keymap_config_return_query() {
FILE: crates/atuin/src/command/client/search/keybindings/actions.rs
type Action (line 7) | pub enum Action {
method from_str (line 79) | pub fn from_str(s: &str) -> Result<Self, String> {
method as_str (line 157) | pub fn as_str(&self) -> String {
method fmt (line 222) | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
method deserialize (line 234) | fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, ...
method serialize (line 228) | fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Er...
function parse_basic_actions (line 245) | fn parse_basic_actions() {
function parse_accept_nth (line 257) | fn parse_accept_nth() {
function parse_return_selection (line 263) | fn parse_return_selection() {
function parse_unknown_action (line 279) | fn parse_unknown_action() {
function round_trip (line 288) | fn round_trip() {
function serde_round_trip (line 306) | fn serde_round_trip() {
FILE: crates/atuin/src/command/client/search/keybindings/conditions.rs
type ConditionAtom (line 7) | pub enum ConditionAtom {
method evaluate (line 63) | pub fn evaluate(&self, ctx: &EvalContext) -> bool {
method from_str (line 80) | pub fn from_str(s: &str) -> Result<Self, String> {
method as_str (line 96) | pub fn as_str(&self) -> &'static str {
method fmt (line 112) | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
type ConditionExpr (line 31) | pub enum ConditionExpr {
method evaluate (line 123) | pub fn evaluate(&self, ctx: &EvalContext) -> bool {
method from (line 138) | fn from(atom: ConditionAtom) -> Self {
method not (line 146) | pub fn not(self) -> Self {
method and (line 151) | pub fn and(self, other: ConditionExpr) -> Self {
method or (line 156) | pub fn or(self, other: ConditionExpr) -> Self {
method parse (line 289) | pub fn parse(s: &str) -> Result<Self, String> {
method prec (line 309) | fn prec(&self) -> Prec {
method fmt_with_prec (line 318) | fn fmt_with_prec(&self, f: &mut fmt::Formatter<'_>, parent_prec: Prec)...
method fmt (line 348) | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
method deserialize (line 364) | fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, ...
type EvalContext (line 40) | pub struct EvalContext {
type ExprParser (line 176) | struct ExprParser<'a> {
function new (line 182) | fn new(input: &'a str) -> Self {
function skip_whitespace (line 186) | fn skip_whitespace(&mut self) {
function starts_with (line 192) | fn starts_with(&mut self, s: &str) -> bool {
function consume (line 197) | fn consume(&mut self, s: &str) -> bool {
function parse (line 208) | fn parse(mut self) -> Result<ConditionExpr, String> {
function parse_or (line 222) | fn parse_or(&mut self) -> Result<ConditionExpr, String> {
function parse_and (line 233) | fn parse_and(&mut self) -> Result<ConditionExpr, String> {
function parse_unary (line 244) | fn parse_unary(&mut self) -> Result<ConditionExpr, String> {
function parse_primary (line 254) | fn parse_primary(&mut self) -> Result<ConditionExpr, String> {
function parse_atom (line 267) | fn parse_atom(&mut self) -> Result<ConditionExpr, String> {
type Prec (line 301) | enum Prec {
method serialize (line 358) | fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Er...
function ctx (line 378) | fn ctx(
function ctx_with_original (line 388) | fn ctx_with_original(
function atom_cursor_at_start (line 410) | fn atom_cursor_at_start() {
function atom_cursor_at_end (line 416) | fn atom_cursor_at_end() {
function atom_input_empty (line 423) | fn atom_input_empty() {
function atom_original_input_empty (line 429) | fn atom_original_input_empty() {
function atom_list_at_end (line 445) | fn atom_list_at_end() {
function atom_list_at_start (line 452) | fn atom_list_at_start() {
function atom_no_results_and_has_results (line 459) | fn atom_no_results_and_has_results() {
function atom_has_context (line 467) | fn atom_has_context() {
function atom_parse_round_trip (line 475) | fn atom_parse_round_trip() {
function atom_parse_unknown (line 493) | fn atom_parse_unknown() {
function parse_bare_atom (line 500) | fn parse_bare_atom() {
function parse_negation (line 506) | fn parse_negation() {
function parse_double_negation (line 515) | fn parse_double_negation() {
function parse_and (line 526) | fn parse_and() {
function parse_or (line 538) | fn parse_or() {
function parse_precedence_and_binds_tighter_than_or (line 550) | fn parse_precedence_and_binds_tighter_than_or() {
function parse_parens_override_precedence (line 566) | fn parse_parens_override_precedence() {
function parse_complex_nested (line 582) | fn parse_complex_nested() {
function parse_whitespace_tolerance (line 600) | fn parse_whitespace_tolerance() {
function parse_error_unknown_atom (line 609) | fn parse_error_unknown_atom() {
function parse_error_trailing_input (line 614) | fn parse_error_trailing_input() {
function parse_error_unmatched_paren (line 619) | fn parse_error_unmatched_paren() {
function parse_error_empty (line 624) | fn parse_error_empty() {
function eval_not (line 631) | fn eval_not() {
function eval_and (line 640) | fn eval_and() {
function eval_or (line 651) | fn eval_or() {
function eval_complex_nested (line 662) | fn eval_complex_nested() {
function display_atom (line 679
Condensed preview — 418 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (2,409K chars).
[
{
"path": ".cargo/audit.toml",
"chars": 302,
"preview": "[advisories]\nignore = [\n # This is a vuln on RSA. RSA is in our lockfile, but not in cargo-tree. \n # It is a issue wit"
},
{
"path": ".codespellrc",
"chars": 250,
"preview": "[codespell]\n# Ref: https://github.com/codespell-project/codespell#using-a-config-file\nskip = .git*,*.lock,.codespellrc,C"
},
{
"path": ".dockerignore",
"chars": 20,
"preview": "./target\nDockerfile\n"
},
{
"path": ".gitattributes",
"chars": 52,
"preview": "*.sh eol=lf\n*.nix eol=lf\n*.zsh eol=lf\n\n*.sql eol=lf\n"
},
{
"path": ".github/DISCUSSION_TEMPLATE/support.yml",
"chars": 2258,
"preview": "body:\n - type: input\n attributes:\n label: Operating System\n description: What operating system are you usi"
},
{
"path": ".github/FUNDING.yml",
"chars": 735,
"preview": "# These are supported funding model platforms\n\ngithub: [atuinsh]\npatreon: # Replace with a single Patreon username\nopen_"
},
{
"path": ".github/ISSUE_TEMPLATE/bug.yaml",
"chars": 1178,
"preview": "name: Bug Report\ndescription: File a bug report\ntitle: \"[Bug]: \"\nlabels: [\"bug\", \"triage\"]\nbody:\n - type: markdown\n "
},
{
"path": ".github/dependabot.yml",
"chars": 764,
"preview": "# To get started with Dependabot version updates, you'll need to specify which\n# package ecosystems to update and where "
},
{
"path": ".github/pull_request_template.md",
"chars": 408,
"preview": "<!-- Thank you for making a PR! Bug fixes are always welcome, but if you're adding a new feature or changing an existing"
},
{
"path": ".github/workflows/codespell.yml",
"chars": 607,
"preview": "# Codespell configuration is within .codespellrc\n---\nname: Codespell\n\non:\n push:\n branches: [main]\n pull_request:\n "
},
{
"path": ".github/workflows/docker.yaml",
"chars": 1318,
"preview": "name: build-docker\n\non:\n push:\n branches: [main]\n\njobs:\n publish:\n concurrency:\n group: ${{ github.ref }}-d"
},
{
"path": ".github/workflows/installer.yml",
"chars": 925,
"preview": "name: Install\n\non:\n push:\n branches: [main]\n pull_request:\n paths: .github/workflows/installer.yml\n\nenv:\n CARGO"
},
{
"path": ".github/workflows/nix.yml",
"chars": 768,
"preview": "# Verify the Nix build is working\n# Failures will usually occur due to an out of date Rust version\n# That can be updated"
},
{
"path": ".github/workflows/release.yml",
"chars": 12661,
"preview": "# This file was autogenerated by dist: https://axodotdev.github.io/cargo-dist\n#\n# Copyright 2022-2024, axodotdev\n# SPDX-"
},
{
"path": ".github/workflows/rust.yml",
"chars": 5711,
"preview": "name: Rust\n\non:\n push:\n branches: [main]\n paths-ignore:\n - \"ui/**\"\n pull_request:\n branches: [main]\n "
},
{
"path": ".github/workflows/shellcheck.yml",
"chars": 309,
"preview": "name: Shellcheck\n\non:\n push:\n branches: [ main ]\n pull_request:\n branches: [ main ]\n\njobs:\n shellcheck:\n run"
},
{
"path": ".github/workflows/update-nix-deps.yml",
"chars": 627,
"preview": "name: Update Nix Deps\non:\n workflow_dispatch: # allows manual triggering\n schedule:\n - cron: '0 0 1 * *' # runs mon"
},
{
"path": ".gitignore",
"chars": 137,
"preview": ".DS_Store\n/target\n*/target\n.env\n.idea/\n.vscode/\nresult\npublish.sh\n.envrc\n.planning/\n\nui/backend/target\nui/backend/gen\n\ns"
},
{
"path": ".mailmap",
"chars": 804,
"preview": "networkException <git@nwex.de> <github@nwex.de>\nViolet Shreve <github@shreve.io> <jacob@shreve.io>\nChris Rose <offline@o"
},
{
"path": ".rustfmt.toml",
"chars": 114,
"preview": "reorder_imports = true\n# uncomment once stable\n#imports_granularity = \"crate\"\n#group_imports = \"StdExternalCrate\"\n"
},
{
"path": "AGENTS.md",
"chars": 3351,
"preview": "# Atuin\n\nShell history tool. Replaces your shell's built-in history with a SQLite database, adds context (cwd, exit code"
},
{
"path": "CHANGELOG.md",
"chars": 72237,
"preview": "# Changelog\n\nAll notable changes to this project will be documented in this file.\n\n## [unreleased]\n\n### Bug Fixes\n\n- Nus"
},
{
"path": "CODE_OF_CONDUCT.md",
"chars": 5225,
"preview": "# Contributor Covenant Code of Conduct\n\n## Our Pledge\n\nWe as members, contributors, and leaders pledge to make participa"
},
{
"path": "CONTRIBUTING.md",
"chars": 4074,
"preview": "# Contributing\n\nThank you so much for considering contributing to Atuin! We really appreciate it <3\n\nDevelopment depende"
},
{
"path": "CONTRIBUTORS",
"chars": 9633,
"preview": "0x4A6F <0x4A6F@users.noreply.github.com>\nAleks Bunin <sashkab@users.noreply.github.com>\nAlex Hamilton <1622250+Aehmlo@us"
},
{
"path": "Cargo.toml",
"chars": 2914,
"preview": "[workspace]\nmembers = [\"crates/*\", \"crates/atuin-nucleo/matcher\", \"crates/atuin-nucleo/bench\"]\n\nresolver = \"2\"\nexclude ="
},
{
"path": "Dockerfile",
"chars": 940,
"preview": "FROM lukemathwalker/cargo-chef:latest-rust-1.94.0-slim-bookworm AS chef\nWORKDIR app\n\nFROM chef AS planner\nCOPY . .\nRUN c"
},
{
"path": "LICENSE",
"chars": 1071,
"preview": "MIT License\n\nCopyright (c) 2021 Ellie Huxtable\n\nPermission is hereby granted, free of charge, to any person obtaining a "
},
{
"path": "README.md",
"chars": 4529,
"preview": "<p align=\"center\">\n <picture>\n <source media=\"(prefers-color-scheme: dark)\" srcset=\"https://github.com/atuinsh/atuin/as"
},
{
"path": "atuin.nix",
"chars": 1270,
"preview": "# Atuin package definition\n#\n# This file will be similar to the package definition in nixpkgs:\n# https://github.com/"
},
{
"path": "atuin.plugin.zsh",
"chars": 148,
"preview": "# shellcheck disable=2148,SC2168,SC1090,SC2125\nlocal FOUND_ATUIN=$+commands[atuin]\n\nif [[ $FOUND_ATUIN -eq 1 ]]; then\n "
},
{
"path": "cliff.toml",
"chars": 3458,
"preview": "# git-cliff ~ default configuration file\n# https://git-cliff.org/docs/configuration\n#\n# Lines starting with \"#\" are comm"
},
{
"path": "crates/atuin/Cargo.toml",
"chars": 3561,
"preview": "[package]\nname = \"atuin\"\nedition = \"2024\"\ndescription = \"atuin - magical shell history\"\nreadme = \"./README.md\"\n\nrust-ver"
},
{
"path": "crates/atuin/LICENSE",
"chars": 1071,
"preview": "MIT License\n\nCopyright (c) 2021 Ellie Huxtable\n\nPermission is hereby granted, free of charge, to any person obtaining a "
},
{
"path": "crates/atuin/build.rs",
"chars": 303,
"preview": "use std::process::Command;\nfn main() {\n let output = Command::new(\"git\").args([\"rev-parse\", \"HEAD\"]).output();\n\n l"
},
{
"path": "crates/atuin/src/command/client/account/change_password.rs",
"chars": 1873,
"preview": "use clap::Parser;\nuse eyre::{Result, bail};\n\nuse atuin_client::{\n auth::{self, MutateResponse},\n settings::Setting"
},
{
"path": "crates/atuin/src/command/client/account/delete.rs",
"chars": 1515,
"preview": "use atuin_client::{\n auth::{self, MutateResponse},\n settings::Settings,\n};\nuse clap::Parser;\nuse eyre::{Result, ba"
},
{
"path": "crates/atuin/src/command/client/account/link.rs",
"chars": 1357,
"preview": "use eyre::{Result, bail};\n\nuse atuin_client::settings::Settings;\n\npub async fn run(settings: &Settings) -> Result<()> {\n"
},
{
"path": "crates/atuin/src/command/client/account/login.rs",
"chars": 10483,
"preview": "use std::{io, path::PathBuf};\n\nuse clap::Parser;\nuse eyre::{Context, Result, bail};\nuse tokio::{fs::File, io::AsyncWrite"
},
{
"path": "crates/atuin/src/command/client/account/logout.rs",
"chars": 97,
"preview": "use eyre::Result;\n\npub async fn run() -> Result<()> {\n atuin_client::logout::logout().await\n}\n"
},
{
"path": "crates/atuin/src/command/client/account/register.rs",
"chars": 4569,
"preview": "use clap::Parser;\nuse eyre::{Result, bail};\n\nuse super::login::or_user_input;\nuse atuin_client::{\n auth::{self, AuthR"
},
{
"path": "crates/atuin/src/command/client/account.rs",
"chars": 1269,
"preview": "use clap::{Args, Subcommand};\nuse eyre::Result;\n\nuse atuin_client::record::sqlite_store::SqliteStore;\nuse atuin_client::"
},
{
"path": "crates/atuin/src/command/client/daemon.rs",
"chars": 21532,
"preview": "use std::fs::{self, File, OpenOptions};\nuse std::io::{ErrorKind, Write};\n#[cfg(unix)]\nuse std::os::unix::net::UnixStream"
},
{
"path": "crates/atuin/src/command/client/default_config.rs",
"chars": 104,
"preview": "use atuin_client::settings::Settings;\n\npub fn run() {\n println!(\"{}\", Settings::example_config());\n}\n"
},
{
"path": "crates/atuin/src/command/client/doctor.rs",
"chars": 12522,
"preview": "use std::process::Command;\nuse std::{env, str::FromStr};\n\nuse atuin_client::database::Sqlite;\nuse atuin_client::settings"
},
{
"path": "crates/atuin/src/command/client/dotfiles/alias.rs",
"chars": 5455,
"preview": "use clap::{Subcommand, ValueEnum};\nuse eyre::{Context, Result, eyre};\n\nuse atuin_client::{encryption, record::sqlite_sto"
},
{
"path": "crates/atuin/src/command/client/dotfiles/var.rs",
"chars": 5634,
"preview": "use clap::{Subcommand, ValueEnum};\nuse eyre::{Context, Result};\n\nuse atuin_client::{encryption, record::sqlite_store::Sq"
},
{
"path": "crates/atuin/src/command/client/dotfiles.rs",
"chars": 677,
"preview": "use clap::Subcommand;\nuse eyre::Result;\n\nuse atuin_client::{record::sqlite_store::SqliteStore, settings::Settings};\n\nmod"
},
{
"path": "crates/atuin/src/command/client/history.rs",
"chars": 27319,
"preview": "use std::{\n fmt::{self, Display},\n io::{self, IsTerminal, Write},\n path::PathBuf,\n time::Duration,\n};\n\nuse a"
},
{
"path": "crates/atuin/src/command/client/import.rs",
"chars": 6583,
"preview": "use std::env;\n\nuse async_trait::async_trait;\nuse clap::Parser;\nuse eyre::Result;\nuse indicatif::ProgressBar;\n\nuse atuin_"
},
{
"path": "crates/atuin/src/command/client/info.rs",
"chars": 1019,
"preview": "use atuin_client::settings::Settings;\r\n\r\nuse crate::{SHA, VERSION};\r\n\r\npub fn run(settings: &Settings) {\r\n let config"
},
{
"path": "crates/atuin/src/command/client/init/bash.rs",
"chars": 1488,
"preview": "use atuin_client::settings::Tmux;\nuse atuin_dotfiles::store::{AliasStore, var::VarStore};\nuse eyre::Result;\n\nfn print_tm"
},
{
"path": "crates/atuin/src/command/client/init/fish.rs",
"chars": 3153,
"preview": "use atuin_client::settings::Tmux;\nuse atuin_dotfiles::store::{AliasStore, var::VarStore};\nuse eyre::Result;\n\nfn print_tm"
},
{
"path": "crates/atuin/src/command/client/init/powershell.rs",
"chars": 1134,
"preview": "use atuin_client::settings::Tmux;\nuse atuin_dotfiles::store::{AliasStore, var::VarStore};\n\npub fn init_static(disable_up"
},
{
"path": "crates/atuin/src/command/client/init/xonsh.rs",
"chars": 1119,
"preview": "use atuin_client::settings::Tmux;\nuse atuin_dotfiles::store::{AliasStore, var::VarStore};\nuse eyre::Result;\n\npub fn init"
},
{
"path": "crates/atuin/src/command/client/init/zsh.rs",
"chars": 1940,
"preview": "use atuin_client::settings::Tmux;\nuse atuin_dotfiles::store::{AliasStore, var::VarStore};\nuse eyre::Result;\n\nfn print_tm"
},
{
"path": "crates/atuin/src/command/client/init.rs",
"chars": 6280,
"preview": "use std::path::PathBuf;\n\nuse atuin_client::{\n encryption,\n record::sqlite_store::SqliteStore,\n settings::{Setti"
},
{
"path": "crates/atuin/src/command/client/kv.rs",
"chars": 3952,
"preview": "use std::io::{self, IsTerminal, Read};\n\nuse clap::Subcommand;\nuse eyre::{Context, Result, eyre};\n\nuse atuin_client::{enc"
},
{
"path": "crates/atuin/src/command/client/scripts.rs",
"chars": 19903,
"preview": "use std::collections::HashMap;\nuse std::collections::HashSet;\nuse std::io::IsTerminal;\nuse std::io::Read;\nuse std::path:"
},
{
"path": "crates/atuin/src/command/client/search/cursor.rs",
"chars": 12612,
"preview": "use atuin_client::settings::WordJumpMode;\n\npub struct Cursor {\n source: String,\n index: usize,\n}\n\nimpl From<String"
},
{
"path": "crates/atuin/src/command/client/search/duration.rs",
"chars": 2236,
"preview": "use core::fmt;\nuse std::{ops::ControlFlow, time::Duration};\n\n#[allow(clippy::module_name_repetitions)]\npub fn format_dur"
},
{
"path": "crates/atuin/src/command/client/search/engines/daemon.rs",
"chars": 7003,
"preview": "use async_trait::async_trait;\nuse atuin_client::{\n database::{Database, OptFilters},\n history::History,\n settin"
},
{
"path": "crates/atuin/src/command/client/search/engines/db.rs",
"chars": 3468,
"preview": "use super::{SearchEngine, SearchState};\nuse async_trait::async_trait;\nuse atuin_client::{\n database::Database,\n da"
},
{
"path": "crates/atuin/src/command/client/search/engines/skim.rs",
"chars": 8112,
"preview": "use std::path::Path;\n\nuse async_trait::async_trait;\nuse atuin_client::{database::Database, history::History, settings::F"
},
{
"path": "crates/atuin/src/command/client/search/engines.rs",
"chars": 2755,
"preview": "use async_trait::async_trait;\nuse atuin_client::{\n database::{Context, Database},\n history::{History, HistoryId},\n"
},
{
"path": "crates/atuin/src/command/client/search/history_list.rs",
"chars": 14423,
"preview": "use std::time::Duration;\n\nuse super::duration::format_duration;\nuse super::engines::SearchEngine;\nuse atuin_client::{\n "
},
{
"path": "crates/atuin/src/command/client/search/inspector.rs",
"chars": 13128,
"preview": "use std::time::Duration;\nuse time::macros::format_description;\n\nuse atuin_client::{\n history::{History, HistoryStats}"
},
{
"path": "crates/atuin/src/command/client/search/interactive.rs",
"chars": 109968,
"preview": "use std::{\n io::{IsTerminal, Write, stdout},\n time::Duration,\n};\n\n#[cfg(unix)]\nuse std::io::Read as _;\n\nuse atuin_"
},
{
"path": "crates/atuin/src/command/client/search/keybindings/actions.rs",
"chars": 11972,
"preview": "use std::fmt;\n\nuse serde::{Deserialize, Deserializer, Serialize, Serializer};\n\n/// All possible actions that can be trig"
},
{
"path": "crates/atuin/src/command/client/search/keybindings/conditions.rs",
"chars": 26471,
"preview": "use std::fmt;\n\nuse serde::{Deserialize, Deserializer, Serialize, Serializer};\n\n/// Atomic (leaf) conditions that can be "
},
{
"path": "crates/atuin/src/command/client/search/keybindings/defaults.rs",
"chars": 45431,
"preview": "use std::collections::HashMap;\n\nuse atuin_client::settings::{KeyBindingConfig, Settings};\nuse tracing::warn;\n\nuse super:"
},
{
"path": "crates/atuin/src/command/client/search/keybindings/key.rs",
"chars": 22103,
"preview": "use std::fmt;\n\nuse ratatui::crossterm::event::{KeyCode, KeyEvent, KeyModifiers, MediaKeyCode};\nuse serde::{Deserialize, "
},
{
"path": "crates/atuin/src/command/client/search/keybindings/keymap.rs",
"chars": 7193,
"preview": "use std::collections::HashMap;\n\nuse super::actions::Action;\nuse super::conditions::{ConditionExpr, EvalContext};\nuse sup"
},
{
"path": "crates/atuin/src/command/client/search/keybindings/mod.rs",
"chars": 376,
"preview": "pub mod actions;\npub mod conditions;\npub mod defaults;\npub mod key;\npub mod keymap;\n\npub use actions::Action;\n#[allow(un"
},
{
"path": "crates/atuin/src/command/client/search.rs",
"chars": 11866,
"preview": "use std::fs::File;\nuse std::io::{IsTerminal as _, Write, stderr, stdout};\n\nuse atuin_common::utils::{self, Escapable as "
},
{
"path": "crates/atuin/src/command/client/setup.rs",
"chars": 2368,
"preview": "use atuin_client::settings::Settings;\n\nuse colored::Colorize;\nuse eyre::Result;\nuse std::io::{self, Write};\nuse toml_edi"
},
{
"path": "crates/atuin/src/command/client/stats.rs",
"chars": 2725,
"preview": "use clap::Parser;\nuse eyre::Result;\nuse interim::parse_date_string;\nuse time::{Duration, OffsetDateTime, Time};\n\nuse atu"
},
{
"path": "crates/atuin/src/command/client/store/pull.rs",
"chars": 2328,
"preview": "use clap::Args;\nuse eyre::Result;\n\nuse atuin_client::{\n database::Database,\n record::store::Store,\n record::syn"
},
{
"path": "crates/atuin/src/command/client/store/purge.rs",
"chars": 632,
"preview": "use clap::Args;\nuse eyre::Result;\n\nuse atuin_client::{\n encryption::load_key,\n record::{sqlite_store::SqliteStore,"
},
{
"path": "crates/atuin/src/command/client/store/push.rs",
"chars": 3127,
"preview": "use atuin_common::record::HostId;\nuse clap::Args;\nuse eyre::Result;\nuse uuid::Uuid;\n\nuse atuin_client::{\n api_client:"
},
{
"path": "crates/atuin/src/command/client/store/rebuild.rs",
"chars": 2824,
"preview": "use atuin_dotfiles::store::{AliasStore, var::VarStore};\nuse atuin_scripts::store::ScriptStore;\nuse clap::Args;\nuse eyre:"
},
{
"path": "crates/atuin/src/command/client/store/rekey.rs",
"chars": 2059,
"preview": "use clap::Args;\nuse eyre::{Result, bail};\nuse tokio::{fs::File, io::AsyncWriteExt};\n\nuse atuin_client::{\n encryption:"
},
{
"path": "crates/atuin/src/command/client/store/verify.rs",
"chars": 664,
"preview": "use clap::Args;\nuse eyre::Result;\n\nuse atuin_client::{\n encryption::load_key,\n record::{sqlite_store::SqliteStore,"
},
{
"path": "crates/atuin/src/command/client/store.rs",
"chars": 3668,
"preview": "use clap::Subcommand;\nuse eyre::Result;\n\nuse atuin_client::{\n database::Database,\n record::{sqlite_store::SqliteSt"
},
{
"path": "crates/atuin/src/command/client/sync/status.rs",
"chars": 1387,
"preview": "use crate::{SHA, VERSION};\nuse atuin_client::{api_client, database::Database, settings::Settings};\nuse colored::Colorize"
},
{
"path": "crates/atuin/src/command/client/sync.rs",
"chars": 4005,
"preview": "use clap::Subcommand;\nuse eyre::{Result, WrapErr};\n\nuse atuin_client::{\n database::Database,\n encryption,\n hist"
},
{
"path": "crates/atuin/src/command/client/wrapped.rs",
"chars": 11758,
"preview": "use crossterm::style::{ResetColor, SetAttribute};\nuse eyre::Result;\nuse std::collections::{HashMap, HashSet};\nuse time::"
},
{
"path": "crates/atuin/src/command/client.rs",
"chars": 12035,
"preview": "use std::fs::{self, OpenOptions};\nuse std::path::{Path, PathBuf};\n\nuse clap::Subcommand;\nuse eyre::{Result, WrapErr};\n\nu"
},
{
"path": "crates/atuin/src/command/contributors.rs",
"chars": 110,
"preview": "static CONTRIBUTORS: &str = include_str!(\"CONTRIBUTORS\");\n\npub fn run() {\n println!(\"\\n{CONTRIBUTORS}\");\n}\n"
},
{
"path": "crates/atuin/src/command/external.rs",
"chars": 2594,
"preview": "use std::fmt::Write as _;\nuse std::process::Command;\nuse std::{io, process};\n\n#[cfg(feature = \"client\")]\nuse atuin_clien"
},
{
"path": "crates/atuin/src/command/gen_completions.rs",
"chars": 2407,
"preview": "use clap::{CommandFactory, Parser, ValueEnum};\nuse clap_complete::{Generator, Shell, generate, generate_to};\nuse clap_co"
},
{
"path": "crates/atuin/src/command/mod.rs",
"chars": 1726,
"preview": "use clap::Subcommand;\nuse eyre::Result;\n\n#[cfg(not(windows))]\nuse rustix::{fs::Mode, process::umask};\n\n#[cfg(feature = \""
},
{
"path": "crates/atuin/src/main.rs",
"chars": 1329,
"preview": "#![warn(clippy::pedantic, clippy::nursery)]\n#![allow(clippy::use_self, clippy::missing_const_for_fn)] // not 100% reliab"
},
{
"path": "crates/atuin/src/shell/.gitattributes",
"chars": 9,
"preview": "* eol=lf\n"
},
{
"path": "crates/atuin/src/shell/atuin.bash",
"chars": 29609,
"preview": "# Include guard\nif [[ ${__atuin_initialized-} == true ]]; then\n false\nelif [[ $- != *i* ]]; then\n # Enable only in"
},
{
"path": "crates/atuin/src/shell/atuin.fish",
"chars": 4804,
"preview": "if not set -q ATUIN_SESSION; or test \"$ATUIN_SHLVL\" != \"$SHLVL\"\n set -gx ATUIN_SESSION (atuin uuid)\n set -gx ATUIN"
},
{
"path": "crates/atuin/src/shell/atuin.nu",
"chars": 3337,
"preview": "# Source this in your ~/.config/nushell/config.nu\n# minimum supported version = 0.93.0\nmodule compat {\n export def --wr"
},
{
"path": "crates/atuin/src/shell/atuin.ps1",
"chars": 10476,
"preview": "# Atuin PowerShell module\n#\n# This should support PowerShell 5.1 (which is shipped with Windows) and later versions, on "
},
{
"path": "crates/atuin/src/shell/atuin.xsh",
"chars": 3012,
"preview": "import subprocess\n\nfrom prompt_toolkit.application.current import get_app\nfrom prompt_toolkit.filters import Condition\nf"
},
{
"path": "crates/atuin/src/shell/atuin.zsh",
"chars": 5666,
"preview": "# shellcheck disable=SC2034,SC2153,SC2086,SC2155\n\n# Above line is because shellcheck doesn't support zsh, per\n# https://"
},
{
"path": "crates/atuin/src/sync.rs",
"chars": 1831,
"preview": "use atuin_dotfiles::store::{AliasStore, var::VarStore};\nuse atuin_scripts::store::ScriptStore;\nuse eyre::{Context, Resul"
},
{
"path": "crates/atuin/tests/common/mod.rs",
"chars": 3662,
"preview": "use std::{env, time::Duration};\n\nuse atuin_client::api_client;\nuse atuin_common::utils::uuid_v7;\nuse atuin_server::{Sett"
},
{
"path": "crates/atuin/tests/sync.rs",
"chars": 1281,
"preview": "use atuin_common::{api::AddHistoryRequest, utils::uuid_v7};\nuse time::OffsetDateTime;\n\nmod common;\n\n#[tokio::test]\nasync"
},
{
"path": "crates/atuin/tests/users.rs",
"chars": 3776,
"preview": "use atuin_common::utils::uuid_v7;\n\nmod common;\n\n#[tokio::test]\nasync fn registration() {\n let path = format!(\"/{}\", u"
},
{
"path": "crates/atuin-ai/Cargo.toml",
"chars": 1259,
"preview": "[package]\nname = \"atuin-ai\"\nedition = \"2024\"\ndescription = \"AI integration for Atuin CLI\"\n\nrust-version = { workspace = "
},
{
"path": "crates/atuin-ai/render-tests.sh",
"chars": 951,
"preview": "#!/bin/bash\n# Render all test cases from test-renders.json\n# Usage: ./render-tests.sh [test_name]\n# With no args: rend"
},
{
"path": "crates/atuin-ai/replay-states.sh",
"chars": 3131,
"preview": "#!/bin/bash\n# Replay state snapshots from a debug state JSONL file\n# Usage: ./replay-states.sh <state-file.jsonl> [entry"
},
{
"path": "crates/atuin-ai/src/commands/debug_render.rs",
"chars": 14863,
"preview": "//! Debug render command for TUI development\n//!\n//! Takes JSON state as input and outputs a single rendered frame as te"
},
{
"path": "crates/atuin-ai/src/commands/init.rs",
"chars": 8215,
"preview": "use crate::commands::detect_shell;\n\npub async fn run(shell: String) -> eyre::Result<()> {\n let integration = match sh"
},
{
"path": "crates/atuin-ai/src/commands/inline.rs",
"chars": 27680,
"preview": "use crate::commands::detect_shell;\nuse crate::tui::render::render;\nuse crate::tui::{\n App, AppEvent, AppMode, Convers"
},
{
"path": "crates/atuin-ai/src/commands.rs",
"chars": 5706,
"preview": "use std::{\n fs,\n path::{Path, PathBuf},\n};\n\nuse atuin_common::shell::Shell;\nuse clap::{Args, Subcommand};\nuse eyre"
},
{
"path": "crates/atuin-ai/src/lib.rs",
"chars": 31,
"preview": "pub mod commands;\npub mod tui;\n"
},
{
"path": "crates/atuin-ai/src/tui/app.rs",
"chars": 5296,
"preview": "use super::state::{AppMode, AppState, ExitAction};\nuse crossterm::event::{KeyCode, KeyEvent, KeyModifiers};\nuse tui_text"
},
{
"path": "crates/atuin-ai/src/tui/component.rs",
"chars": 5947,
"preview": "//! Component-oriented rendering primitives for the TUI.\n//!\n//! Defines the `Component` trait and container types (`VSt"
},
{
"path": "crates/atuin-ai/src/tui/components.rs",
"chars": 16604,
"preview": "//! Leaf components for each content type and factory functions for building\n//! the component tree from the view model."
},
{
"path": "crates/atuin-ai/src/tui/event.rs",
"chars": 10132,
"preview": "use crate::tui::App;\nuse crossterm::event::{Event, EventStream, KeyEvent, KeyEventKind};\nuse eyre::{Result, eyre};\nuse f"
},
{
"path": "crates/atuin-ai/src/tui/mod.rs",
"chars": 483,
"preview": "pub mod app;\npub mod component;\npub mod components;\npub mod event;\n#[cfg(unix)]\npub mod popup;\npub mod render;\npub mod s"
},
{
"path": "crates/atuin-ai/src/tui/popup.rs",
"chars": 12288,
"preview": "use ratatui::layout::Rect;\n\n/// Maximum popup height (lines). Keeps context visible around the popup.\nconst MAX_POPUP_HE"
},
{
"path": "crates/atuin-ai/src/tui/render.rs",
"chars": 8926,
"preview": "use atuin_client::theme::{Meaning, Theme};\nuse pulldown_cmark::{Event, Parser, Tag, TagEnd};\nuse ratatui::{\n Frame,\n "
},
{
"path": "crates/atuin-ai/src/tui/spinner.rs",
"chars": 2998,
"preview": "//! Spinner styles and configuration for TUI animations\n//!\n//! To experiment with different spinners, change `ACTIVE_SP"
},
{
"path": "crates/atuin-ai/src/tui/state.rs",
"chars": 17604,
"preview": "//! Domain state types for the TUI application\n//!\n//! This module contains the core state types that represent the appl"
},
{
"path": "crates/atuin-ai/src/tui/terminal.rs",
"chars": 10349,
"preview": "use crossterm::{\n cursor,\n terminal::{disable_raw_mode, enable_raw_mode},\n};\nuse eyre::{Context, Result, bail};\nus"
},
{
"path": "crates/atuin-ai/src/tui/view_model.rs",
"chars": 15618,
"preview": "//! View model types for the TUI application\n//!\n//! This module contains the view model types that represent the render"
},
{
"path": "crates/atuin-ai/test-renders.json",
"chars": 10405,
"preview": "[\n {\n \"name\": \"01_empty_input\",\n \"description\": \"Initial state with empty input prompt\",\n \"state\": {\n \"ev"
},
{
"path": "crates/atuin-client/Cargo.toml",
"chars": 2394,
"preview": "[package]\nname = \"atuin-client\"\nedition = \"2024\"\ndescription = \"client library for atuin\"\n\nrust-version = { workspace = "
},
{
"path": "crates/atuin-client/config.toml",
"chars": 14235,
"preview": "## Base directory for Atuin data files (databases, keys, session, etc.)\n## All data file paths default to being relative"
},
{
"path": "crates/atuin-client/meta-migrations/20260203030924_create_meta.sql",
"chars": 161,
"preview": "create table if not exists meta (\n key text not null primary key,\n value text not null,\n updated_at integer not"
},
{
"path": "crates/atuin-client/migrations/20210422143411_create_history.sql",
"chars": 440,
"preview": "-- Add migration script here\ncreate table if not exists history (\n\tid text primary key,\n\ttimestamp integer not null,\n\tdu"
},
{
"path": "crates/atuin-client/migrations/20220505083406_create-events.sql",
"chars": 312,
"preview": "create table if not exists events (\n\tid text primary key,\n\ttimestamp integer not null,\n\thostname text not null,\n\tevent_t"
},
{
"path": "crates/atuin-client/migrations/20220806155627_interactive_search_index.sql",
"chars": 216,
"preview": "-- Interactive search filters by command then by the max(timestamp) for that\n-- command. Create an index that covers tho"
},
{
"path": "crates/atuin-client/migrations/20230315220114_drop-events.sql",
"chars": 48,
"preview": "-- Add migration script here\ndrop table events;\n"
},
{
"path": "crates/atuin-client/migrations/20230319185725_deleted_at.sql",
"chars": 80,
"preview": "-- Add migration script here\nalter table history add column deleted_at integer;\n"
},
{
"path": "crates/atuin-client/migrations/20260224000100_history_author_intent.sql",
"chars": 88,
"preview": "alter table history add column author text;\nalter table history add column intent text;\n"
},
{
"path": "crates/atuin-client/record-migrations/20230531212437_create-records.sql",
"chars": 419,
"preview": "-- Add migration script here\ncreate table if not exists records (\n id text primary key,\n parent text unique, -- null i"
},
{
"path": "crates/atuin-client/record-migrations/20231127090831_create-store.sql",
"chars": 417,
"preview": "-- Add migration script here\ncreate table if not exists store (\n id text primary key, -- globally unique ID\n\n idx in"
},
{
"path": "crates/atuin-client/src/api_client.rs",
"chars": 13351,
"preview": "use std::collections::HashMap;\nuse std::env;\nuse std::time::Duration;\n\nuse eyre::{Result, bail, eyre};\nuse reqwest::{\n "
},
{
"path": "crates/atuin-client/src/auth.rs",
"chars": 14124,
"preview": "use async_trait::async_trait;\nuse eyre::{Context, Result, bail};\nuse reqwest::{StatusCode, Url, header::USER_AGENT};\nuse"
},
{
"path": "crates/atuin-client/src/database.rs",
"chars": 46656,
"preview": "use std::{\n env,\n path::{Path, PathBuf},\n str::FromStr,\n time::Duration,\n};\n\nuse async_trait::async_trait;\nu"
},
{
"path": "crates/atuin-client/src/distro.rs",
"chars": 2691,
"preview": "use std::process::Command;\n\n/// Detect the Linux distribution from the system,\n/// using system-specific release files a"
},
{
"path": "crates/atuin-client/src/encryption.rs",
"chars": 16826,
"preview": "// The general idea is that we NEVER send cleartext history to the server\n// This way the odds of anything private endin"
},
{
"path": "crates/atuin-client/src/history/builder.rs",
"chars": 4401,
"preview": "use typed_builder::TypedBuilder;\n\nuse super::History;\n\n/// Builder for a history entry that is imported from shell histo"
},
{
"path": "crates/atuin-client/src/history/store.rs",
"chars": 14439,
"preview": "use std::{collections::HashSet, fmt::Write, time::Duration};\n\nuse eyre::{Result, bail, eyre};\nuse indicatif::{ProgressBa"
},
{
"path": "crates/atuin-client/src/history.rs",
"chars": 25691,
"preview": "use core::fmt::Formatter;\nuse rmp::decode::DecodeStringError;\nuse rmp::decode::ValueReadError;\nuse rmp::{Marker, decode:"
},
{
"path": "crates/atuin-client/src/hub.rs",
"chars": 9805,
"preview": "//! Hub authentication support for Atuin\n//!\n//! This module provides programmatic access to the Atuin Hub authenticatio"
},
{
"path": "crates/atuin-client/src/import/bash.rs",
"chars": 6619,
"preview": "use std::{path::PathBuf, str};\n\nuse async_trait::async_trait;\nuse directories::UserDirs;\nuse eyre::{Result, eyre};\nuse i"
},
{
"path": "crates/atuin-client/src/import/fish.rs",
"chars": 5494,
"preview": "// import old shell history!\n// automatically hoover up all that we can find\n\nuse std::path::PathBuf;\n\nuse async_trait::"
},
{
"path": "crates/atuin-client/src/import/mod.rs",
"chars": 2792,
"preview": "use std::fs::File;\nuse std::io::Read;\nuse std::path::PathBuf;\n\nuse async_trait::async_trait;\nuse eyre::{Result, bail};\nu"
},
{
"path": "crates/atuin-client/src/import/nu.rs",
"chars": 1710,
"preview": "// import old shell history!\n// automatically hoover up all that we can find\n\nuse std::path::PathBuf;\n\nuse async_trait::"
},
{
"path": "crates/atuin-client/src/import/nu_histdb.rs",
"chars": 3323,
"preview": "// import old shell history!\n// automatically hoover up all that we can find\n\nuse std::path::PathBuf;\n\nuse async_trait::"
},
{
"path": "crates/atuin-client/src/import/powershell.rs",
"chars": 5907,
"preview": "use async_trait::async_trait;\nuse directories::BaseDirs;\nuse eyre::{Result, eyre};\nuse std::path::PathBuf;\nuse time::{Du"
},
{
"path": "crates/atuin-client/src/import/replxx.rs",
"chars": 4460,
"preview": "use std::{path::PathBuf, str};\n\nuse async_trait::async_trait;\nuse directories::UserDirs;\nuse eyre::{Result, eyre};\nuse t"
},
{
"path": "crates/atuin-client/src/import/resh.rs",
"chars": 4404,
"preview": "use std::path::PathBuf;\n\nuse async_trait::async_trait;\nuse directories::UserDirs;\nuse eyre::{Result, eyre};\nuse serde::D"
},
{
"path": "crates/atuin-client/src/import/xonsh.rs",
"chars": 8029,
"preview": "use std::env;\nuse std::fs::{self, File};\nuse std::path::{Path, PathBuf};\n\nuse async_trait::async_trait;\nuse directories:"
},
{
"path": "crates/atuin-client/src/import/xonsh_sqlite.rs",
"chars": 7180,
"preview": "use std::env;\nuse std::path::PathBuf;\n\nuse async_trait::async_trait;\nuse directories::BaseDirs;\nuse eyre::{Result, eyre}"
},
{
"path": "crates/atuin-client/src/import/zsh.rs",
"chars": 7037,
"preview": "// import old shell history!\n// automatically hoover up all that we can find\n\nuse std::borrow::Cow;\nuse std::path::PathB"
},
{
"path": "crates/atuin-client/src/import/zsh_histdb.rs",
"chars": 8539,
"preview": "// import old shell history from zsh-histdb!\n// automatically hoover up all that we can find\n\n// As far as i can tell th"
},
{
"path": "crates/atuin-client/src/lib.rs",
"chars": 528,
"preview": "#![deny(unsafe_code)]\n\n#[macro_use]\nextern crate log;\n\n#[cfg(feature = \"sync\")]\npub mod api_client;\n#[cfg(feature = \"syn"
},
{
"path": "crates/atuin-client/src/login.rs",
"chars": 2746,
"preview": "use std::path::PathBuf;\n\nuse atuin_common::api::LoginRequest;\nuse eyre::{Context, Result, bail};\nuse tokio::fs::File;\nus"
},
{
"path": "crates/atuin-client/src/logout.rs",
"chars": 367,
"preview": "use eyre::Result;\n\nuse crate::settings::Settings;\n\npub async fn logout() -> Result<()> {\n let meta = Settings::meta_s"
},
{
"path": "crates/atuin-client/src/meta.rs",
"chars": 12396,
"preview": "use std::path::Path;\nuse std::str::FromStr;\nuse std::time::Duration;\n\nuse atuin_common::record::HostId;\nuse eyre::{Resul"
},
{
"path": "crates/atuin-client/src/ordering.rs",
"chars": 1151,
"preview": "use minspan::minspan;\n\nuse super::{history::History, settings::SearchMode};\n\npub fn reorder_fuzzy(mode: SearchMode, quer"
},
{
"path": "crates/atuin-client/src/plugin.rs",
"chars": 2602,
"preview": "use std::collections::HashMap;\n\n#[derive(Debug, Clone)]\npub struct OfficialPlugin {\n pub name: String,\n pub descri"
},
{
"path": "crates/atuin-client/src/record/encryption.rs",
"chars": 13140,
"preview": "use atuin_common::record::{\n AdditionalData, DecryptedData, EncryptedData, Encryption, HostId, RecordId, RecordIdx,\n}"
},
{
"path": "crates/atuin-client/src/record/mod.rs",
"chars": 97,
"preview": "pub mod encryption;\npub mod sqlite_store;\npub mod store;\n\n#[cfg(feature = \"sync\")]\npub mod sync;\n"
},
{
"path": "crates/atuin-client/src/record/sqlite_store.rs",
"chars": 19369,
"preview": "// Here we are using sqlite as a pretty dumb store, and will not be running any complex queries.\n// Multiple stores of m"
},
{
"path": "crates/atuin-client/src/record/store.rs",
"chars": 2130,
"preview": "use async_trait::async_trait;\nuse eyre::Result;\n\nuse atuin_common::record::{EncryptedData, HostId, Record, RecordId, Rec"
},
{
"path": "crates/atuin-client/src/record/sync.rs",
"chars": 19887,
"preview": "// do a sync :O\nuse std::{cmp::Ordering, fmt::Write};\n\nuse eyre::Result;\nuse thiserror::Error;\n\nuse super::store::Store;"
},
{
"path": "crates/atuin-client/src/register.rs",
"chars": 501,
"preview": "use eyre::Result;\n\nuse crate::{api_client, settings::Settings};\n\npub async fn register_classic(\n settings: &Settings,"
},
{
"path": "crates/atuin-client/src/secrets.rs",
"chars": 5384,
"preview": "// This file will probably trigger a lot of scanners. Sorry.\n\nuse regex::RegexSet;\nuse std::sync::LazyLock;\n\npub enum Te"
},
{
"path": "crates/atuin-client/src/settings/dotfiles.rs",
"chars": 173,
"preview": "use serde::{Deserialize, Serialize};\n\n#[derive(Debug, Serialize, Deserialize, Clone, Default)]\npub struct Settings {\n "
},
{
"path": "crates/atuin-client/src/settings/kv.rs",
"chars": 371,
"preview": "use serde::{Deserialize, Serialize};\n\n#[derive(Debug, Serialize, Deserialize, Clone)]\npub struct Settings {\n pub db_p"
},
{
"path": "crates/atuin-client/src/settings/meta.rs",
"chars": 373,
"preview": "use serde::{Deserialize, Serialize};\n\n#[derive(Debug, Serialize, Deserialize, Clone)]\npub struct Settings {\n pub db_p"
},
{
"path": "crates/atuin-client/src/settings/scripts.rs",
"chars": 376,
"preview": "use serde::{Deserialize, Serialize};\n\n#[derive(Debug, Serialize, Deserialize, Clone)]\npub struct Settings {\n pub db_p"
},
{
"path": "crates/atuin-client/src/settings/watcher.rs",
"chars": 9538,
"preview": "//! Config file watching for automatic settings reload.\n//!\n//! This module provides a `SettingsWatcher` that monitors t"
},
{
"path": "crates/atuin-client/src/settings.rs",
"chars": 61642,
"preview": "use std::{collections::HashMap, fmt, io::prelude::*, path::PathBuf, str::FromStr, sync::OnceLock};\nuse tokio::sync::Once"
},
{
"path": "crates/atuin-client/src/sync.rs",
"chars": 6420,
"preview": "use std::collections::HashSet;\nuse std::iter::FromIterator;\n\nuse eyre::Result;\n\nuse atuin_common::api::AddHistoryRequest"
},
{
"path": "crates/atuin-client/src/theme.rs",
"chars": 27251,
"preview": "use config::{Config, File as ConfigFile, FileFormat};\nuse log;\nuse palette::named;\nuse serde::{Deserialize, Serialize};\n"
},
{
"path": "crates/atuin-client/src/utils.rs",
"chars": 520,
"preview": "pub(crate) fn get_hostname() -> String {\n std::env::var(\"ATUIN_HOST_NAME\")\n .unwrap_or_else(|_| whoami::hostna"
},
{
"path": "crates/atuin-client/tests/data/xonsh/xonsh-82eafbf5-9f43-489a-80d2-61c7dc6ef542.json",
"chars": 7452,
"preview": "{\"locs\": [ 69, 3371, 3451, 3978],\n \"index\": {\"offsets\":{\"__total__\":0,\"cmds\":[{\"__total__\":10,\""
},
{
"path": "crates/atuin-client/tests/data/xonsh/xonsh-de16af90-9148-4461-8df3-5b5659c6420d.json",
"chars": 7411,
"preview": "{\"locs\": [ 69, 3372, 3452, 3936],\n \"index\": {\"offsets\":{\"__total__\":0,\"cmds\":[{\"__total__\":10,\""
},
{
"path": "crates/atuin-common/Cargo.toml",
"chars": 834,
"preview": "[package]\nname = \"atuin-common\"\nedition = \"2024\"\ndescription = \"common library for atuin\"\n\nrust-version = { workspace = "
},
{
"path": "crates/atuin-common/src/api.rs",
"chars": 3508,
"preview": "use semver::Version;\nuse serde::{Deserialize, Serialize};\nuse std::borrow::Cow;\nuse std::sync::LazyLock;\nuse time::Offse"
},
{
"path": "crates/atuin-common/src/calendar.rs",
"chars": 268,
"preview": "// Calendar data\nuse serde::{Serialize, Deserialize};\n\npub enum TimePeriod {\n YEAR,\n MONTH,\n DAY,\n}\n\n#[derive(D"
},
{
"path": "crates/atuin-common/src/lib.rs",
"chars": 1491,
"preview": "#![deny(unsafe_code)]\n\n/// Defines a new UUID type wrapper\nmacro_rules! new_uuid {\n ($name:ident) => {\n #[deri"
},
{
"path": "crates/atuin-common/src/record.rs",
"chars": 12855,
"preview": "use std::collections::HashMap;\n\nuse eyre::Result;\nuse serde::{Deserialize, Serialize};\nuse typed_builder::TypedBuilder;\n"
},
{
"path": "crates/atuin-common/src/shell.rs",
"chars": 5373,
"preview": "use std::{ffi::OsStr, path::Path, process::Command};\n\nuse serde::Serialize;\nuse sysinfo::{Process, System, get_current_p"
},
{
"path": "crates/atuin-common/src/tls.rs",
"chars": 465,
"preview": "use std::sync::Once;\n\nstatic INIT: Once = Once::new();\n\n/// Ensure the rustls crypto provider (ring) is installed.\n///\n/"
},
{
"path": "crates/atuin-common/src/utils.rs",
"chars": 10094,
"preview": "use std::borrow::Cow;\nuse std::env;\nuse std::path::PathBuf;\n\nuse eyre::{Result, eyre};\n\nuse base64::prelude::{BASE64_URL"
},
{
"path": "crates/atuin-daemon/Cargo.toml",
"chars": 1392,
"preview": "[package]\nname = \"atuin-daemon\"\nedition = \"2024\"\nversion = { workspace = true }\ndescription = \"The daemon crate for Atui"
},
{
"path": "crates/atuin-daemon/build.rs",
"chars": 778,
"preview": "use std::{env, fs, path::PathBuf};\n\nuse protox::prost::Message;\n\nfn main() -> std::io::Result<()> {\n let proto_paths "
},
{
"path": "crates/atuin-daemon/proto/control.proto",
"chars": 1521,
"preview": "syntax = \"proto3\";\npackage control;\n\n// The Control service allows external processes (CLI commands, etc.)\n// to inject "
},
{
"path": "crates/atuin-daemon/proto/history.proto",
"chars": 1102,
"preview": "syntax = \"proto3\";\npackage history;\n\nmessage StartHistoryRequest {\n // If people are still using my software in ~530 ye"
},
{
"path": "crates/atuin-daemon/proto/search.proto",
"chars": 671,
"preview": "syntax = \"proto3\";\npackage search;\n\nenum FilterMode {\n GLOBAL = 0;\n HOST = 1;\n SESSION = 2;\n DIRECTORY = 3;\n WORKSP"
},
{
"path": "crates/atuin-daemon/src/client.rs",
"chars": 13781,
"preview": "use atuin_client::database::Context;\nuse atuin_client::settings::{FilterMode, Settings};\nuse eyre::{Context as EyreConte"
},
{
"path": "crates/atuin-daemon/src/components/history.rs",
"chars": 7944,
"preview": "//! History component.\n//!\n//! Handles command history lifecycle (start/end) and provides the History gRPC service.\n\nuse"
},
{
"path": "crates/atuin-daemon/src/components/mod.rs",
"chars": 574,
"preview": "//! Daemon components.\n//!\n//! Components are the building blocks of the daemon. Each component handles\n//! a specific d"
},
{
"path": "crates/atuin-daemon/src/components/search.rs",
"chars": 15391,
"preview": "//! Search component.\n//!\n//! Provides fuzzy search over command history using the Nucleo search library\n//! with frecen"
},
{
"path": "crates/atuin-daemon/src/components/sync.rs",
"chars": 9812,
"preview": "//! Sync component.\n//!\n//! Handles periodic synchronization with the Atuin cloud server.\n\nuse std::time::Duration;\n\nuse"
},
{
"path": "crates/atuin-daemon/src/control/mod.rs",
"chars": 340,
"preview": "//! Control module for external event injection.\n//!\n//! This module provides the gRPC service that allows external proc"
},
{
"path": "crates/atuin-daemon/src/control/service.rs",
"chars": 2301,
"preview": "//! Control service implementation.\n//!\n//! This gRPC service allows external processes (like CLI commands) to inject\n//"
}
]
// ... and 218 more files (download for full content)
About this extraction
This page contains the full source code of the atuinsh/atuin GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 418 files (2.2 MB), approximately 594.9k tokens, and a symbol index with 2615 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.