App-orgadb

 view release on metacpan or  search on metacpan

script/orgadb-sel  view on Meta::CPAN

#!perl

use 5.010001;
use strict;
use warnings;

our $AUTHORITY = 'cpan:PERLANCAR'; # AUTHORITY
our $DATE = '2025-06-19'; # DATE
our $DIST = 'App-orgadb'; # DIST
our $VERSION = '0.020'; # VERSION

use Perinci::CmdLine::Any;

my $cmdline = Perinci::CmdLine::Any->new(
    summary => 'Select entries and fields from Org addressbook',
    url => '/App/orgadb/select',
    log => 1,
    config_filename => ['orgadb.conf', 'orgadb-sel.conf'],
);

$cmdline->run;

# ABSTRACT: Select entries and fields from Org addressbook
# PODNAME: orgadb-sel

__END__

=pod

=encoding UTF-8

=head1 NAME

orgadb-sel - Select entries and fields from Org addressbook

=head1 VERSION

This document describes version 0.020 of orgadb-sel (from Perl distribution App-orgadb), released on 2025-06-19.

=head1 SYNOPSIS

B<B<orgadb-sel>> [B<L<--category|/"--category=s, -c">>=I<L<str_or_re|Sah::Schema::str_or_re>>|B<L<-c|/"--category=s, -c">>=I<L<str_or_re|Sah::Schema::str_or_re>>] [B<L<--clipboard|/"-y">>=I<str>|B<L<-Y|/"-y">>|B<L<--clipboard-only|/"-y">>|B<L<-y|/"-y...

First, create a configuration file F<~/.config/orgadb.conf> containing something
like the following (use INI syntax, or L<IOD> to be more exact):

 ; specify your addressbook files here
 files = ~/addressbook.org
 files = /path/to/another-addressbook.org

Suppose you have F<~/addressbook.org> like the following (entries are written as
level-2 headings, level 1 is used for categories, hierarchical categories can be
written using breadcrumb-style notation with ">" separator):

 * family
 ** iwan
 - home phone :: 555-1234-567
 - cell :: 555-8765-432
 - address ::
   + street :: Jl Mangga 123
   + city :: Bandung
   + postcode :: 40123
   + country :: Indonesia
 ** restu
 - cell :: 555-1234-568
 ** satya

 * family > wife's
 ** roger
 ** emily
 ** cynthia

 * work > acme inc
 ** bugs
 ** daffy

 * work > acme inc > ex
 ** marvin

 * work > newsradio
 ** dave
 ** lisa
 - cell :: 555-1234-710
 - home phone :: 555-1234-712
 - note ::
   + [2022-07-03] :: do not call after office hours
 ** joe
 - cell :: 555-1234-569
 - cell :: 555-1234-570
 ** beth

 * work > newsradio > ex
 ** matthew

=head2 Listing all entries

To list all entries (categories will be shown as path prefix):

 % orgadb-sel
 ** family/iwan
 ** family/restu
 ** family/satya

script/orgadb-sel  view on Meta::CPAN

   + [2022-07-03] :: do not call after office hours

 % orgadb-sel lisa -Cl  ;# do not show the category
 ** lisa
 - cell :: 555-1234-710
 - home phone :: 555-1234-712
 - note ::
   + [2022-07-03] :: do not call after office hours

 % orgadb-sel lisa -El  ;# do not show the entry line
 - cell :: 555-1234-710
 - home phone :: 555-1234-712
 - note ::
   + [2022-07-03] :: do not call after office hours

=head2 Filtering entries by the fields they have

Aside from by category, we can filter entries by the fields they have. For
example, to only list entries that have 'bank information' field:

 % orgadb-sel --filter-entries-by-fields '/bank information/'

Another example, to only include entries that have 'deceased' field set to
'true' or 'y/'yes':

 % orgadb-sel --filter-entries-by-fields '/deceased/ = /(?:true|yes|y)/i'

=head2 Searching fields

To get Lisa's cell phone number (search against field name):

 % orgadb-sel lisa cell
 ** work > newsradio/lisa
 - cell :: 555-1234-710

To get Lisa's cell phone number (only the number, without the entry headline or
the field name):

 % orgadb-sel lisa cell -E -N
 555-1234-710

To get all Lisa's phone numbers:

 % orgadb-sel lisa -E '/phone|cell/'
 - cell :: 555-1234-710
 - home phone :: 555-1234-712

You can also search subfields. For example, to show Iwan's postcode field value
under the address field:

 % orgadb-sel iwan address postcode -EN
 40123

=head2 Formatting

You can apply one or more formatters to field values:

 % orgadb-sel lisa cell --formatter Str::remove_non_digit -EN
 5551234710

=head2 Copying to clipboard

Instead of just displaying result to terminal, you can instruct to also copy
matching field values to clipboard with the `--clipboard=tee` (`-y`) option:

 % orgadb-sel lisa cell -y
 ** work > newsradio/lisa
 - cell :: 555-1234-710

(and clipboard will contain C<555-1234-710>).

You can also instruct to only output matching field values to clipboard and not
print matching fields to terminal using the `--clipboard=only` (`-Y`) option:

 % orgadb-sel lisa cell -Y
 ** work > newsradio/lisa

(and clipboard will contain C<555-1234-710>).

=head2 Shell mode

Instead of selecting one time and exiting, you can instruct B<orgadb-sel> to
enter shell mode, where you can issue multiple select commands without
re-reading the Org addressbook files repeatedly. For example:

 % orgadb-sel -s
 > select lisa
 ...
 > select lisa -l
 ...
 > select lisa cell -E -N
 ...
 > exit

 % _

When the addressbook files change on disk, the files will be re-read.

=head2 Password book

Aside from a regular addressbook, you can also use B<orgadb-sel> with password
books (a file you store passwords in). B<orgadb-sel> can read GnuPG-encrypted
files, where the decrypted content is read into memory and not stored in
temporary files. You can then use shell mode (C<-s>) to repeatedly query the
password book without re-reading and re-decrypting everytime. For example,
suppose you have a password book like this:

 # -*- Mode: org -*-
 * persona > perlancar
 ** google (perlancar)
 - username :: perlancar
 - pass :: secret1
 - security question :: favorite dog in the whole wide world?
 - security answer :: impossible to pick one
 - log ::
   + [2022-07-04 Mon] :: change password
   + [2017-08-01] :: create
 ** twitter (perlancar)
 - username :: perlancar
 - pass :: secret2
 * persona > steven
 ** google (steven123123)
 - username :: steven123123
 - phone :: 555-123-2345
 - pass :: secret3

and you store it in C<~/passwords.gpg>. Then to query passwords:

 # What's my (perlancar)'s google password?
 % orgadb-sel -f ~/passwords.gpg /google.+perlancar/ pass -EN
 secret1

 # What's my (steven)'s phone used in the google account?
 % orgadb-sel -f ~/passwords.gpg /google.+steven/ '/phone|cell/' -EN
 555-123-2345

Or, in shell mode:

 % orgadb-sel -f ~/passwords.gpg -s
 > select /google.+perlancar/ pass -EN
 secret1
 > select /google.+steven/ '/phone|cell/' -EN
 555-123-2345
 > exit

 % _

The C<--clipboard=only> (C<-Y>) option is handy when querying password book; you
can choose to output field values only to clipboard instead of to terminal:

 # What's my (perlancar)'s google password?
 % orgadb-sel -f ~/passwords.gpg /google.+perlancar/ pass -EN -Y

=head1 DESCRIPTION

B<App::orgadb> is a set of CLIs for addressbook written in Org format. It
currently contains:

=over

=item * orgadb-sel

CLI to list/select addressbook entries and fields.

=back

The addressbook must be written following a certain structure, as shown in the
Synopsis. The first heading level is for putting categories. The second heading
level is where you put all your entries. Fields are written in description list.

=head1 TIPS AND TRICKS

=head2 Aliasing orgadb-sel to a shorter command name

If you are like me and you select from addressbooks a lot, you might want to
alias C<orgadb-sel> to a shorter name, e.g. C<sel>. To do this, create this
script somewhere in your PATH:

 #!/usr/bin/env perl
 # FRAGMENT id=shcompgen-hint command=orgadb-sel
 exec "orgadb-sel", @ARGV;

The C<# FRAGMENT> line is optional (it's useful if you use L<shcompgen>). In
your bash startup file, put something like:

 complete -C orgadb-sel sel

or if you L<shcompgen>, run C<shcompgen gen sel> instead.

=head2 Tab completion

The script provides tab completion for category, entry, and field, so you can
type:

 % orgadb-sel --category <tab>        ;# see what categories are available
 % orgadb-sel lis<tab>                ;# complete with entries matching 'lis'
 % orgadb-sel lisa <tab>              ;# complete with available fields of /lisa/ entries

=head2 Using field formatters

Suppose you want to format phone number using international notation:

 % orgadb-sel lisa phone -f Phone::format

=head2 Using default field formatter rules

Instead of specifying formatters everytime, you can setup rules for default
formatters in the configuration file:

 default_formatter_rules={"hide_field_name":true, "formatters":["Str::remove_comment"]}
 default_formatter_rules={"field_name_matches":"/te?lp|wa|phone|whatsapp|hp/i","hide_field_name":true,  "formatters":["Phone::format_idn_nospace"]}
 default_formatter_rules={"field_name_matches":"/te?lp|wa|phone|whatsapp|hp/i","hide_field_name":false, "formatters":["Phone::format_idn"]}

and after this, when you select they will automatically be applied when
selecting matching fields:

 % orgadb-sel lisa phone

To disable formatters, use C<--no-formatters> (C<-F>).

=head2 Copying to clipboard

Instead of manually copy-pasting the result of C<orgadb-sel> using your mouse in
the terminal and pasting to other GUI application (like LibreOffice Writer/Calc,
WhatsApp Web in Firefox, or whatever), you can instruct C<orgadb-sel> to copy to
clipboard for you:

 % orgadb-sel -c lisa phone

=head1 OPTIONS

C<*> marks required options.

=head2 Main options

=over

=item B<--count>

Return just the number of matching entries instead of showing them.

=item B<--entry-match-mode>=I<s>

How entry should be matched.

Default value:

 "default"

Valid values:

 ["default","exact","exact-ci"]

The default matching mode is as follow:

 str       Substring matching
 /re/      Regular expression matching

If matching mode is set to C<exact>, then matching will be done by string
equality test. This mode is basically a shorter alternative to having to
specify:

 /^\Qre\E$/

Matching mode C<exact-ci> is like C<exact> except case-insensitive. It is
equivalent to:

 /^\Qre\E$/i


=item B<--field-match-mode>=I<s>

How entry should be matched.

Default value:

 "default"

Valid values:

 ["default","exact","exact-ci"]

The default matching mode is as follow:

 str       Substring matching
 /re/      Regular expression matching

script/orgadb-sel  view on Meta::CPAN


=item B<--no-reload-files-on-change>

(No description)


=back

=head2 Logging options

=over

=item B<--debug>

Shortcut for --log-level=debug.

=item B<--log-level>=I<s>

Set log level.

By default, these log levels are available (in order of increasing level of
importance, from least important to most): C<trace>, C<debug>, C<info>,
C<warn>/C<warning>, C<error>, C<fatal>. By default, the level is usually set to
C<warn>, which means that log statements with level C<info> and less important
levels will not be shown. To increase verbosity, choose C<info>, C<debug>, or
C<trace>.

For more details on log level and logging, as well as how new logging levels can
be defined or existing ones modified, see L<Log::ger>.


=item B<--quiet>

Shortcut for --log-level=error.

=item B<--trace>

Shortcut for --log-level=trace.

=item B<--verbose>

Shortcut for --log-level=info.

=back

=head2 Mode options

=over

=item B<--shell>, B<-s>

(No description)


=back

=head2 Output options

=over

=item B<--clipboard-only>

Shortcut for --clipboard=only.

See C<--clipboard>.

=item B<--clipboard>=I<s>

Whether to copy matching field values to clipboard.

Valid values:

 ["tee","only"]

If set to C<tee>, then will display matching fields to terminal as well as copy
matching field values to clipboard.

If set to C<only>, then will not display matching fields to terminal and will
only copy matching field values to clipboard.

Mnemonic for short option C<-y> and C<-Y>: I<y>ank as in Emacs (C<C-y>).


=item B<--detail>, B<-l>

Instead of showing matching field values, display the whole entry.

Mnemonic for shortcut option C<-l>: the option C<-l> is usually used for the short
version of C<--detail>, as in I<ls> Unix command.


=item B<--field-value-formatter-rules-json>=I<s>

See C<--field-value-formatter-rules>.

=item B<--field-value-formatter-rules>=I<s>

Specify field value formatters to use when conditions are met, specified as an
array of hashes. Each element is a rule that is as a hash containing condition
keys and formatters keys. If all conditions are met then the formatters will be
applied. The rules will be tested when each field is about to be outputted.
Multiple rules can match and the matching rules' formatters are all applied in
succession.

Note that this option will be overridden by the C<--field-value-formatter>
(C<-fvfmt>) or the C<--no-field-value-formatters> (C<-F>) option.

The rules are best specified in the configuration as opposed to on the
command-line option. An example (the lines below are writen in configuration
file in IOD syntax, as rows of JSON hashes):

 ; remove all comments in field values when 'hide_field_name' option is set
 ; (which usually means we want to copy paste things)
 
 field_value_formatter_rules={"hide_field_name":true, "formatters":[ ["Str::remove_comment"] ]}
 
 ; normalize phone numbers using Phone::format + Str::remove_whitespace when
 ; 'hide_field_name' option is set (which usually means we want to copy paste
 ; things). e.g. '0812-1234-5678' becomes '+6281212345678'.
 
 field_value_formatter_rules={"field_name_matches":"/phone|wa|whatsapp/i", "hide_field_name":true, "formatters":[ ["Phone::format", "Str::remove_whitespace"] ]}
 
 ; but if 'hide_field_name' field is not set, normalize phone numbers using
 ; Phone::format without removing whitespaces, which is easier to see (e.g.
 ; '+62 812 1234 5678').
 
 field_value_formatter_rules={"field_name_matches":"/phone|wa|whatsapp/i", "hide_field_name":false, "formatters":[ ["Phone::format"] ]}

Condition keys:

=over

=item * C<field_name_matches> (value: str/re): Check if field name matches a regex pattern.

=item * C<hide_field_name> (value: bool): Check if C<--hide-field-name> (C<-N>) option is
set (true) or unset (false).

=back

script/orgadb-sel  view on Meta::CPAN

=item B<--no-field-value-formatters>, B<--raw-field-values>, B<-F>

Do not apply formatters for field value (overrides --field-value-formatter option).

Note that this option has higher precedence than
C<--default-field-value-formatter-rules> or the C<--field-value-formatter>
(C<--fvfmt>) option.


=item B<--num-entries>=I<s>

Specify maximum number of entries to return (0 means unlimited).

=item B<--num-fields>=I<s>, B<-n>

Specify maximum number of fields (per entry) to return (0 means unlimited).

=item B<--page-result>

Filter output through a pager.

This option will pipe the output to a specified pager program. If pager program
is not specified, a suitable default e.g. C<less> is chosen.


=item B<--remove-comments>

Shortcut for --field-value-formatter Str::remove_comment.

See C<--field-value-formatter>.

=item B<--remove-nondigits>

Shortcut for --field-value-formatter Str::remove_nondigit.

See C<--field-value-formatter>.

=item B<--remove-whitespaces>

Shortcut for --field-value-formatter Str::remove_whitespaces.

See C<--field-value-formatter>.

=item B<--view-result>

View output using a viewer.

This option will first save the output to a temporary file, then open a viewer
program to view the temporary file. If a viewer program is not chosen, a
suitable default, e.g. the browser, is chosen.


=item B<-1>

Shortcut for --num-fields=1.

See C<--num-fields>.

=item B<-Y>

Shortcut for --clipboard=only.

See C<--clipboard>.

=item B<-y>

Shortcut for --clipboard=tee.

See C<--clipboard>.

=back

=head2 Other options

=over

=item B<--help>, B<-h>, B<-?>

Display help message and exit.

=item B<--version>, B<-v>

Display program's version and exit.

=back

=head1 COMPLETION

This script has shell tab completion capability with support for several
shells.

=head2 bash

To activate bash completion for this script, put:

 complete -C orgadb-sel orgadb-sel

in your bash startup (e.g. F<~/.bashrc>). Your next shell session will then
recognize tab completion for the command. Or, you can also directly execute the
line above in your shell to activate immediately.

It is recommended, however, that you install modules using L<cpanm-shcompgen>
which can activate shell completion for scripts immediately.

=head2 tcsh

To activate tcsh completion for this script, put:

 complete orgadb-sel 'p/*/`orgadb-sel`/'

in your tcsh startup (e.g. F<~/.tcshrc>). Your next shell session will then
recognize tab completion for the command. Or, you can also directly execute the
line above in your shell to activate immediately.

It is also recommended to install L<shcompgen> (see above).

=head2 other shells

For fish and zsh, install L<shcompgen> as described above.

=head1 FAQ

=head2 Why doesn't 'orgadb-sel' list all my entries? It returns nothing.

 % orgadb-sel
 % _

Probably because the addressbook is not written following the expected
structure, where the entries should be as I<level-2> headings. You might use the

script/orgadb-sel  view on Meta::CPAN


When queried:

 % orgadb-sel
 friends > high school/jimmy
 friends > high school/john
 friends > high school/jack

=head2 Why can't I search against entry fields? It returns nothing. (I can list entries.)

 % orgadb-sel jimmy cell
 % _

Probably because the addressbook is not written following the expected
structure, where you should use a description list. A common mistake is writing
a description list like this:

 ** jimmy
 - cell: 555-123-4567

This is still an unordered list in Org, you have to use C< :: > (space, followed
by two colons, followed by another space) as the separator:

 ** jimmy
 - cell :: 555-123-4567

=head1 CONFIGURATION FILE

This script can read configuration files. Configuration files are in the format of L<IOD>, which is basically INI with some extra features.

By default, these names are searched for configuration filenames (can be changed using C<--config-path>): F</home/u1/.config/orgadb.conf>, F</home/u1/.config/orgadb-sel.conf>, F</home/u1/orgadb.conf>, F</home/u1/orgadb-sel.conf>, F</etc/orgadb.conf>,...

All found files will be read and merged.

To disable searching for configuration files, pass C<--no-config>.

You can put multiple profiles in a single file by using section names like C<[profile=SOMENAME]> or C<[SOMESECTION profile=SOMENAME]>. Those sections will only be read if you specify the matching C<--config-profile SOMENAME>.

You can also put configuration for multiple programs inside a single file, and use filter C<program=NAME> in section names, e.g. C<[program=NAME ...]> or C<[SOMESECTION program=NAME]>. The section will then only be used when the reading program match...

You can also filter a section by environment variable using the filter C<env=CONDITION> in section names. For example if you only want a section to be read if a certain environment variable is true: C<[env=SOMEVAR ...]> or C<[SOMESECTION env=SOMEVAR ...

To load and configure plugins, you can use either the C<-plugins> parameter (e.g. C<< -plugins=DumpArgs >> or C<< -plugins=DumpArgs@before_validate_args >>), or use the C<[plugin=NAME ...]> sections, for example:

 [plugin=DumpArgs]
 -event=before_validate_args
 -prio=99
 
 [plugin=Foo]
 -event=after_validate_args
 arg1=val1
 arg2=val2

 

which is equivalent to setting C<< -plugins=-DumpArgs@before_validate_args@99,-Foo@after_validate_args,arg1,val1,arg2,val2 >>.

List of available configuration parameters:

 category (see --category)
 clipboard (see --clipboard)
 color (see --color)
 color_theme (see --color-theme)
 count (see --count)
 detail (see --detail)
 entry (see --entry)
 entry_match_mode (see --entry-match-mode)
 field_match_mode (see --field-match-mode)
 field_value_formatter_rules (see --field-value-formatter-rules)
 field_value_formatters (see --field-value-formatter)
 fields (see --field)
 files (see --file)
 filter_entries_by_fields (see --filter-entries-by-field)
 format (see --format)
 hide_category (see --hide-category)
 hide_entry (see --hide-entry)
 hide_field_name (see --hide-field-name)
 log_level (see --log-level)
 naked_res (see --naked-res)
 no_field_value_formatters (see --no-field-value-formatters)
 num_entries (see --num-entries)
 num_fields (see --num-fields)
 reload_files_on_change (see --no-reload-files-on-change)
 shell (see --shell)

=head1 ENVIRONMENT

=head2 ORGADB_SEL_OPT

String. Specify additional command-line options.

=head2 ORGADB_COLOR_THEME

perl::colortheme::modname_with_optional_args. Set default color theme.

Color theme is Perl module name under the C<ColorTheme::Search::> namespace,
without the namespace prefix. The default is C<Light>. You can set color theme
using the C<--color-theme> command-line option as well as this environment
variable.

=head1 FILES

=head2 /home/u1/.config/orgadb.conf

=head2 /home/u1/.config/orgadb-sel.conf

=head2 /home/u1/orgadb.conf

=head2 /home/u1/orgadb-sel.conf

=head2 /etc/orgadb.conf

=head2 /etc/orgadb-sel.conf

=head2 ~/.orgadb_sel_history

Store shell's command history for B<orgadb-sel>.

=head1 HOMEPAGE

Please visit the project's homepage at L<https://metacpan.org/release/App-orgadb>.



( run in 0.544 second using v1.01-cache-2.11-cpan-2398b32b56e )