From e6bce5c9a58d8dee4099f922777f74b9fd7deb51 Mon Sep 17 00:00:00 2001 From: Jnyandeep Date: Thu, 30 Jul 2026 11:05:26 +0530 Subject: [PATCH] feat: export command --- Cargo.lock | 5 +- Cargo.toml | 91 +++++++++++++++++---------------- contrib/completions/_zoxide | 69 +++++++++++++++++++++++++ contrib/completions/_zoxide.ps1 | 32 ++++++++++++ contrib/completions/zoxide.bash | 70 ++++++++++++++++++++++++- contrib/completions/zoxide.elv | 28 ++++++++++ contrib/completions/zoxide.fish | 12 +++++ contrib/completions/zoxide.nu | 21 ++++++++ contrib/completions/zoxide.ts | 55 ++++++++++++++++++++ src/cmd/cmd.rs | 19 +++++++ src/cmd/export.rs | 39 ++++++++++++++ src/cmd/mod.rs | 2 + 12 files changed, 397 insertions(+), 46 deletions(-) create mode 100644 src/cmd/export.rs diff --git a/Cargo.lock b/Cargo.lock index 16edf6e..24c9ed5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -797,9 +797,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.149" +version = "1.0.151" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86" +checksum = "c841b55ecdae098c80dcae9cf767f6f8a0c2cdb3416bbef72181df4d0fe73f14" dependencies = [ "itoa", "memchr", @@ -1171,6 +1171,7 @@ dependencies = [ "rstest", "rstest_reuse", "serde", + "serde_json", "tempfile", "time", "which", diff --git a/Cargo.toml b/Cargo.toml index bfcf408..431ac5c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,8 +18,8 @@ maintenance = { status = "actively-developed" } [dependencies] anyhow = "1.0.32" askama = { version = "0.16.0", default-features = false, features = [ - "derive", - "std", + "derive", + "std", ] } bincode = "1.3.1" clap = { version = "4.3.0", features = ["derive"] } @@ -30,7 +30,12 @@ fastrand = "2.0.0" glob = "0.3.0" ouroboros = "0.18.3" serde = { version = "1.0.116", features = ["derive"] } -time = { version = "0.3.47", default-features = false, features = ["parsing", "macros", "std"] } +serde_json = "1.0.151" +time = { version = "0.3.47", default-features = false, features = [ + "parsing", + "macros", + "std", +] } [target.'cfg(windows)'.dependencies] which = "8.0.2" @@ -60,46 +65,46 @@ strip = true [package.metadata.deb] assets = [ - [ - "target/release/zoxide", - "usr/bin/", - "755", - ], - [ - "contrib/completions/zoxide.bash", - "usr/share/bash-completion/completions/zoxide", - "644", - ], - [ - "contrib/completions/zoxide.fish", - "usr/share/fish/vendor_completions.d/", - "664", - ], - [ - "contrib/completions/_zoxide", - "usr/share/zsh/vendor-completions/", - "644", - ], - [ - "man/man1/*", - "usr/share/man/man1/", - "644", - ], - [ - "README.md", - "usr/share/doc/zoxide/", - "644", - ], - [ - "CHANGELOG.md", - "usr/share/doc/zoxide/", - "644", - ], - [ - "LICENSE", - "usr/share/doc/zoxide/", - "644", - ], + [ + "target/release/zoxide", + "usr/bin/", + "755", + ], + [ + "contrib/completions/zoxide.bash", + "usr/share/bash-completion/completions/zoxide", + "644", + ], + [ + "contrib/completions/zoxide.fish", + "usr/share/fish/vendor_completions.d/", + "664", + ], + [ + "contrib/completions/_zoxide", + "usr/share/zsh/vendor-completions/", + "644", + ], + [ + "man/man1/*", + "usr/share/man/man1/", + "644", + ], + [ + "README.md", + "usr/share/doc/zoxide/", + "644", + ], + [ + "CHANGELOG.md", + "usr/share/doc/zoxide/", + "644", + ], + [ + "LICENSE", + "usr/share/doc/zoxide/", + "644", + ], ] extended-description = """\ zoxide is a smarter cd command, inspired by z and autojump. It remembers which \ diff --git a/contrib/completions/_zoxide b/contrib/completions/_zoxide index 2f4c9f0..9976b09 100644 --- a/contrib/completions/_zoxide +++ b/contrib/completions/_zoxide @@ -94,6 +94,50 @@ _arguments "${_arguments_options[@]}" : \ ;; esac ;; +(export) +_arguments "${_arguments_options[@]}" : \ +'-h[Print help]' \ +'--help[Print help]' \ +'-V[Print version]' \ +'--version[Print version]' \ +":: :_zoxide__subcmd__export_commands" \ +"*::: :->export" \ +&& ret=0 + + case $state in + (export) + words=($line[1] "${words[@]}") + (( CURRENT += 1 )) + curcontext="${curcontext%:*:*}:zoxide-export-command-$line[1]:" + case $line[1] in + (csv) +_arguments "${_arguments_options[@]}" : \ +'-h[Print help]' \ +'--help[Print help]' \ +'-V[Print version]' \ +'--version[Print version]' \ +&& ret=0 +;; +(json) +_arguments "${_arguments_options[@]}" : \ +'-h[Print help]' \ +'--help[Print help]' \ +'-V[Print version]' \ +'--version[Print version]' \ +&& ret=0 +;; +(text) +_arguments "${_arguments_options[@]}" : \ +'-h[Print help]' \ +'--help[Print help]' \ +'-V[Print version]' \ +'--version[Print version]' \ +&& ret=0 +;; + esac + ;; +esac +;; (import) _arguments "${_arguments_options[@]}" : \ '--merge[Merge into existing database]' \ @@ -219,6 +263,7 @@ _zoxide_commands() { local commands; commands=( 'add:Add a new directory or increment its rank' \ 'edit:Edit the database' \ +'export:Export entries from the database' \ 'import:Import entries from another application' \ 'init:Generate shell configuration' \ 'query:Search for a directory in the database' \ @@ -261,6 +306,30 @@ _zoxide__subcmd__edit__subcmd__reload_commands() { local commands; commands=() _describe -t commands 'zoxide edit reload commands' commands "$@" } +(( $+functions[_zoxide__subcmd__export_commands] )) || +_zoxide__subcmd__export_commands() { + local commands; commands=( +'csv:' \ +'json:' \ +'text:' \ + ) + _describe -t commands 'zoxide export commands' commands "$@" +} +(( $+functions[_zoxide__subcmd__export__subcmd__csv_commands] )) || +_zoxide__subcmd__export__subcmd__csv_commands() { + local commands; commands=() + _describe -t commands 'zoxide export csv commands' commands "$@" +} +(( $+functions[_zoxide__subcmd__export__subcmd__json_commands] )) || +_zoxide__subcmd__export__subcmd__json_commands() { + local commands; commands=() + _describe -t commands 'zoxide export json commands' commands "$@" +} +(( $+functions[_zoxide__subcmd__export__subcmd__text_commands] )) || +_zoxide__subcmd__export__subcmd__text_commands() { + local commands; commands=() + _describe -t commands 'zoxide export text commands' commands "$@" +} (( $+functions[_zoxide__subcmd__import_commands] )) || _zoxide__subcmd__import_commands() { local commands; commands=( diff --git a/contrib/completions/_zoxide.ps1 b/contrib/completions/_zoxide.ps1 index a76c12c..fd48c99 100644 --- a/contrib/completions/_zoxide.ps1 +++ b/contrib/completions/_zoxide.ps1 @@ -27,6 +27,7 @@ Register-ArgumentCompleter -Native -CommandName 'zoxide' -ScriptBlock { [CompletionResult]::new('--version', '--version', [CompletionResultType]::ParameterName, 'Print version') [CompletionResult]::new('add', 'add', [CompletionResultType]::ParameterValue, 'Add a new directory or increment its rank') [CompletionResult]::new('edit', 'edit', [CompletionResultType]::ParameterValue, 'Edit the database') + [CompletionResult]::new('export', 'export', [CompletionResultType]::ParameterValue, 'Export entries from the database') [CompletionResult]::new('import', 'import', [CompletionResultType]::ParameterValue, 'Import entries from another application') [CompletionResult]::new('init', 'init', [CompletionResultType]::ParameterValue, 'Generate shell configuration') [CompletionResult]::new('query', 'query', [CompletionResultType]::ParameterValue, 'Search for a directory in the database') @@ -81,6 +82,37 @@ Register-ArgumentCompleter -Native -CommandName 'zoxide' -ScriptBlock { [CompletionResult]::new('--version', '--version', [CompletionResultType]::ParameterName, 'Print version') break } + 'zoxide;export' { + [CompletionResult]::new('-h', '-h', [CompletionResultType]::ParameterName, 'Print help') + [CompletionResult]::new('--help', '--help', [CompletionResultType]::ParameterName, 'Print help') + [CompletionResult]::new('-V', '-V ', [CompletionResultType]::ParameterName, 'Print version') + [CompletionResult]::new('--version', '--version', [CompletionResultType]::ParameterName, 'Print version') + [CompletionResult]::new('csv', 'csv', [CompletionResultType]::ParameterValue, 'csv') + [CompletionResult]::new('json', 'json', [CompletionResultType]::ParameterValue, 'json') + [CompletionResult]::new('text', 'text', [CompletionResultType]::ParameterValue, 'text') + break + } + 'zoxide;export;csv' { + [CompletionResult]::new('-h', '-h', [CompletionResultType]::ParameterName, 'Print help') + [CompletionResult]::new('--help', '--help', [CompletionResultType]::ParameterName, 'Print help') + [CompletionResult]::new('-V', '-V ', [CompletionResultType]::ParameterName, 'Print version') + [CompletionResult]::new('--version', '--version', [CompletionResultType]::ParameterName, 'Print version') + break + } + 'zoxide;export;json' { + [CompletionResult]::new('-h', '-h', [CompletionResultType]::ParameterName, 'Print help') + [CompletionResult]::new('--help', '--help', [CompletionResultType]::ParameterName, 'Print help') + [CompletionResult]::new('-V', '-V ', [CompletionResultType]::ParameterName, 'Print version') + [CompletionResult]::new('--version', '--version', [CompletionResultType]::ParameterName, 'Print version') + break + } + 'zoxide;export;text' { + [CompletionResult]::new('-h', '-h', [CompletionResultType]::ParameterName, 'Print help') + [CompletionResult]::new('--help', '--help', [CompletionResultType]::ParameterName, 'Print help') + [CompletionResult]::new('-V', '-V ', [CompletionResultType]::ParameterName, 'Print version') + [CompletionResult]::new('--version', '--version', [CompletionResultType]::ParameterName, 'Print version') + break + } 'zoxide;import' { [CompletionResult]::new('--merge', '--merge', [CompletionResultType]::ParameterName, 'Merge into existing database') [CompletionResult]::new('-h', '-h', [CompletionResultType]::ParameterName, 'Print help') diff --git a/contrib/completions/zoxide.bash b/contrib/completions/zoxide.bash index 1e6fdcf..6f2a091 100644 --- a/contrib/completions/zoxide.bash +++ b/contrib/completions/zoxide.bash @@ -22,6 +22,9 @@ _zoxide() { zoxide,edit) cmd="zoxide__subcmd__edit" ;; + zoxide,export) + cmd="zoxide__subcmd__export" + ;; zoxide,import) cmd="zoxide__subcmd__import" ;; @@ -46,6 +49,15 @@ _zoxide() { zoxide__subcmd__edit,reload) cmd="zoxide__subcmd__edit__subcmd__reload" ;; + zoxide__subcmd__export,csv) + cmd="zoxide__subcmd__export__subcmd__csv" + ;; + zoxide__subcmd__export,json) + cmd="zoxide__subcmd__export__subcmd__json" + ;; + zoxide__subcmd__export,text) + cmd="zoxide__subcmd__export__subcmd__text" + ;; zoxide__subcmd__import,atuin) cmd="zoxide__subcmd__import__subcmd__atuin" ;; @@ -71,7 +83,7 @@ _zoxide() { case "${cmd}" in zoxide) - opts="-h -V --help --version add edit import init query remove" + opts="-h -V --help --version add edit export import init query remove" if [[ ${cur} == -* || ${COMP_CWORD} -eq 1 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -176,6 +188,62 @@ _zoxide() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; + zoxide__subcmd__export) + opts="-h -V --help --version csv json text" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + zoxide__subcmd__export__subcmd__csv) + opts="-h -V --help --version" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + zoxide__subcmd__export__subcmd__json) + opts="-h -V --help --version" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + zoxide__subcmd__export__subcmd__text) + opts="-h -V --help --version" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; zoxide__subcmd__import) opts="-h -V --merge --help --version atuin autojump fasd z z.lua zsh-z" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then diff --git a/contrib/completions/zoxide.elv b/contrib/completions/zoxide.elv index 5ba33fa..56ffa06 100644 --- a/contrib/completions/zoxide.elv +++ b/contrib/completions/zoxide.elv @@ -24,6 +24,7 @@ set edit:completion:arg-completer[zoxide] = {|@words| cand --version 'Print version' cand add 'Add a new directory or increment its rank' cand edit 'Edit the database' + cand export 'Export entries from the database' cand import 'Import entries from another application' cand init 'Generate shell configuration' cand query 'Search for a directory in the database' @@ -71,6 +72,33 @@ set edit:completion:arg-completer[zoxide] = {|@words| cand -V 'Print version' cand --version 'Print version' } + &'zoxide;export'= { + cand -h 'Print help' + cand --help 'Print help' + cand -V 'Print version' + cand --version 'Print version' + cand csv 'csv' + cand json 'json' + cand text 'text' + } + &'zoxide;export;csv'= { + cand -h 'Print help' + cand --help 'Print help' + cand -V 'Print version' + cand --version 'Print version' + } + &'zoxide;export;json'= { + cand -h 'Print help' + cand --help 'Print help' + cand -V 'Print version' + cand --version 'Print version' + } + &'zoxide;export;text'= { + cand -h 'Print help' + cand --help 'Print help' + cand -V 'Print version' + cand --version 'Print version' + } &'zoxide;import'= { cand --merge 'Merge into existing database' cand -h 'Print help' diff --git a/contrib/completions/zoxide.fish b/contrib/completions/zoxide.fish index 6d7e5b2..b860491 100644 --- a/contrib/completions/zoxide.fish +++ b/contrib/completions/zoxide.fish @@ -28,6 +28,7 @@ complete -c zoxide -n "__fish_zoxide_needs_command" -s h -l help -d 'Print help' complete -c zoxide -n "__fish_zoxide_needs_command" -s V -l version -d 'Print version' complete -c zoxide -n "__fish_zoxide_needs_command" -f -a "add" -d 'Add a new directory or increment its rank' complete -c zoxide -n "__fish_zoxide_needs_command" -f -a "edit" -d 'Edit the database' +complete -c zoxide -n "__fish_zoxide_needs_command" -f -a "export" -d 'Export entries from the database' complete -c zoxide -n "__fish_zoxide_needs_command" -f -a "import" -d 'Import entries from another application' complete -c zoxide -n "__fish_zoxide_needs_command" -f -a "init" -d 'Generate shell configuration' complete -c zoxide -n "__fish_zoxide_needs_command" -f -a "query" -d 'Search for a directory in the database' @@ -49,6 +50,17 @@ complete -c zoxide -n "__fish_zoxide_using_subcommand edit; and __fish_seen_subc complete -c zoxide -n "__fish_zoxide_using_subcommand edit; and __fish_seen_subcommand_from increment" -s V -l version -d 'Print version' complete -c zoxide -n "__fish_zoxide_using_subcommand edit; and __fish_seen_subcommand_from reload" -s h -l help -d 'Print help' complete -c zoxide -n "__fish_zoxide_using_subcommand edit; and __fish_seen_subcommand_from reload" -s V -l version -d 'Print version' +complete -c zoxide -n "__fish_zoxide_using_subcommand export; and not __fish_seen_subcommand_from csv json text" -s h -l help -d 'Print help' +complete -c zoxide -n "__fish_zoxide_using_subcommand export; and not __fish_seen_subcommand_from csv json text" -s V -l version -d 'Print version' +complete -c zoxide -n "__fish_zoxide_using_subcommand export; and not __fish_seen_subcommand_from csv json text" -f -a "csv" +complete -c zoxide -n "__fish_zoxide_using_subcommand export; and not __fish_seen_subcommand_from csv json text" -f -a "json" +complete -c zoxide -n "__fish_zoxide_using_subcommand export; and not __fish_seen_subcommand_from csv json text" -f -a "text" +complete -c zoxide -n "__fish_zoxide_using_subcommand export; and __fish_seen_subcommand_from csv" -s h -l help -d 'Print help' +complete -c zoxide -n "__fish_zoxide_using_subcommand export; and __fish_seen_subcommand_from csv" -s V -l version -d 'Print version' +complete -c zoxide -n "__fish_zoxide_using_subcommand export; and __fish_seen_subcommand_from json" -s h -l help -d 'Print help' +complete -c zoxide -n "__fish_zoxide_using_subcommand export; and __fish_seen_subcommand_from json" -s V -l version -d 'Print version' +complete -c zoxide -n "__fish_zoxide_using_subcommand export; and __fish_seen_subcommand_from text" -s h -l help -d 'Print help' +complete -c zoxide -n "__fish_zoxide_using_subcommand export; and __fish_seen_subcommand_from text" -s V -l version -d 'Print version' complete -c zoxide -n "__fish_zoxide_using_subcommand import; and not __fish_seen_subcommand_from atuin autojump fasd z z.lua zsh-z" -l merge -d 'Merge into existing database' complete -c zoxide -n "__fish_zoxide_using_subcommand import; and not __fish_seen_subcommand_from atuin autojump fasd z z.lua zsh-z" -s h -l help -d 'Print help' complete -c zoxide -n "__fish_zoxide_using_subcommand import; and not __fish_seen_subcommand_from atuin autojump fasd z z.lua zsh-z" -s V -l version -d 'Print version' diff --git a/contrib/completions/zoxide.nu b/contrib/completions/zoxide.nu index 4d07049..1fb78a8 100644 --- a/contrib/completions/zoxide.nu +++ b/contrib/completions/zoxide.nu @@ -43,6 +43,27 @@ module completions { --version(-V) # Print version ] + # Export entries from the database + export extern "zoxide export" [ + --help(-h) # Print help + --version(-V) # Print version + ] + + export extern "zoxide export csv" [ + --help(-h) # Print help + --version(-V) # Print version + ] + + export extern "zoxide export json" [ + --help(-h) # Print help + --version(-V) # Print version + ] + + export extern "zoxide export text" [ + --help(-h) # Print help + --version(-V) # Print version + ] + # Import entries from another application export extern "zoxide import" [ --merge # Merge into existing database diff --git a/contrib/completions/zoxide.ts b/contrib/completions/zoxide.ts index 207da2f..12b26bc 100644 --- a/contrib/completions/zoxide.ts +++ b/contrib/completions/zoxide.ts @@ -111,6 +111,61 @@ const completion: Fig.Spec = { }, ], }, + { + name: "export", + description: "Export entries from the database", + subcommands: [ + { + name: "csv", + options: [ + { + name: ["-h", "--help"], + description: "Print help", + }, + { + name: ["-V", "--version"], + description: "Print version", + }, + ], + }, + { + name: "json", + options: [ + { + name: ["-h", "--help"], + description: "Print help", + }, + { + name: ["-V", "--version"], + description: "Print version", + }, + ], + }, + { + name: "text", + options: [ + { + name: ["-h", "--help"], + description: "Print help", + }, + { + name: ["-V", "--version"], + description: "Print version", + }, + ], + }, + ], + options: [ + { + name: ["-h", "--help"], + description: "Print help", + }, + { + name: ["-V", "--version"], + description: "Print version", + }, + ], + }, { name: "import", description: "Import entries from another application", diff --git a/src/cmd/cmd.rs b/src/cmd/cmd.rs index 0de2ee5..98b8ac8 100644 --- a/src/cmd/cmd.rs +++ b/src/cmd/cmd.rs @@ -43,6 +43,7 @@ https://github.com/ajeetdsouza/zoxide pub enum Cmd { Add(Add), Edit(Edit), + Export(Export), Import(Import), Init(Init), Query(Query), @@ -88,6 +89,24 @@ pub enum EditCommand { Reload, } +/// Export entries from the database +#[derive(Debug, Parser)] +#[clap( + author, + help_template = HelpTemplate, +)] +pub struct Export { + #[clap(subcommand)] + pub cmd: ExportCommand, +} + +#[derive(Clone, Debug, Subcommand)] +pub enum ExportCommand { + Csv, + Json, + Text, +} + /// Import entries from another application #[derive(Debug, Parser)] #[clap( diff --git a/src/cmd/export.rs b/src/cmd/export.rs new file mode 100644 index 0000000..1844734 --- /dev/null +++ b/src/cmd/export.rs @@ -0,0 +1,39 @@ +use std::io::{self, Write}; + +use serde_json::to_writer_pretty; + +use crate::{ + cmd::{Export, ExportCommand, Run}, + db::Database, + error::BrokenPipeHandler, +}; + +impl Run for Export { + fn run(&self) -> anyhow::Result<()> { + let db = Database::open()?; + let dirs = db.dirs(); + let out = &mut io::stdout().lock(); + + match &self.cmd { + ExportCommand::Csv => { + writeln!(out, "path,rank,last_accessed").pipe_exit("stdout")?; + for dir in dirs { + writeln!(out, "{},{},{}", dir.path, dir.rank, dir.last_accessed) + .pipe_exit("stdout")?; + } + } + ExportCommand::Json => { + to_writer_pretty(&mut *out, dirs)?; + writeln!(out).pipe_exit("stdout")?; + } + ExportCommand::Text => { + for dir in dirs { + writeln!(out, "{}|{}|{}", dir.path, dir.rank, dir.last_accessed) + .pipe_exit("stdout")?; + } + } + } + + Ok(()) + } +} diff --git a/src/cmd/mod.rs b/src/cmd/mod.rs index 5c17474..7cd7d9f 100644 --- a/src/cmd/mod.rs +++ b/src/cmd/mod.rs @@ -1,6 +1,7 @@ mod add; mod cmd; mod edit; +mod export; mod import; mod init; mod query; @@ -20,6 +21,7 @@ impl Run for Cmd { Cmd::Add(cmd) => cmd.run(), Cmd::Edit(cmd) => cmd.run(), Cmd::Import(cmd) => cmd.run(), + Cmd::Export(cmd) => cmd.run(), Cmd::Init(cmd) => cmd.run(), Cmd::Query(cmd) => cmd.run(), Cmd::Remove(cmd) => cmd.run(),