]> nmode's Git Repositories - Fey/blob - lib/App/Fey.pm
7b287f07e185cfeeb2ca1d70adcbbfa923842e7a
[Fey] / lib / App / Fey.pm
1 package App::Fey;
2
3 use strict;
4 use warnings;
5 use Exporter 'import';
6
7 our @EXPORT_OK = qw(fey);
8 our $version = '0.01';
9
10 sub new {
11 my ($class, $options) = @_;
12 my $config = do ($ENV{XDG_CONFIG_HOME} // "$ENV{HOME}/.config") . '/fey/config.pl';
13
14 my $self = {
15 mime_query => $options->{mime_query} // $config->{mime_query} // sub {
16 open my $mime_type, '-|', 'file', '--brief', '--mime-type', $_[0];
17 <$mime_type>;
18 },
19 contexts => $options->{contexts} // $config->{contexts} // { default => sub { 1 } },
20 targets => $options->{targets} // $config->{targets} // {}
21 };
22
23 bless $self, $class;
24 }
25
26 sub launch {
27 my $self = shift;
28 my $options = ref $_[0] ? shift : {};
29
30 die "No files or URIs specified.\n" unless @_;
31
32 if ($options->{group}) {
33 $self->_launch_group($options, @_);
34 } elsif ($options->{single}) {
35 $self->_launch_single($options, @_);
36 } else {
37 $self->_launch($options, @_);
38 }
39 }
40
41 sub _launch {
42 my $self = shift;
43 my $options = shift;
44
45 if ($options->{fork}) {
46 for my $file_or_uri (@_) {
47 my $pid = fork;
48 next if $pid;
49
50 my $handler = $self->_get_handler($options, $file_or_uri);
51 $handler->($file_or_uri) if $handler;
52 return;
53 }
54 } else {
55 for my $file_or_uri (@_) {
56 my $handler = $self->_get_handler($options, $file_or_uri);
57 $handler->($file_or_uri) if $handler;
58 }
59 }
60 }
61
62 sub _launch_group {
63 my $self = shift;
64 my $options = shift;
65
66 my ($groups, $handlers) = ({}, {});
67 for my $file_or_uri (@_) {
68 my $handler = $self->_get_handler($options, $file_or_uri);
69 if ($handler) {
70 $groups->{"$handler"} //= [];
71 push @{ $groups->{"$handler"} }, $file_or_uri;
72 $handlers->{"$handler"} = $handler;
73 }
74 }
75
76 if ($options->{fork}) {
77 for my $group (keys %{ $groups }) {
78 if ($options->{fork}) {
79 my $pid = fork;
80 next if $pid;
81 }
82
83 $handlers->{$group}->(@{ $groups->{$group} });
84 return;
85 }
86 } else {
87 for my $group (keys %{ $groups }) {
88 $handlers->{$group}->(@{ $groups->{$group} });
89 }
90 }
91 }
92
93 sub _launch_single {
94 my $self = shift;
95 my $options = shift;
96
97 if ($options->{fork}) {
98 my $pid = fork;
99 return if $pid;
100 }
101
102 my $handler = $self->_get_handler($options, $_[0]);
103 $handler->(@_) if $handler;
104 }
105
106 sub _get_handler {
107 my $self = shift;
108 my $options = shift;
109
110 my $file_or_uri = $_[0] =~ m|^file://(.+)| ? $1 : $_[0];
111 my $mime_or_uri = -e $file_or_uri ? $self->{mime_query}->($file_or_uri) : $file_or_uri;
112
113 for my $target (@{ $self->{targets} }) {
114 for my $pattern (@{ $target->{patterns} }) {
115 if ($mime_or_uri =~ /$pattern/) {
116 my $associations = $target->{associations};
117
118 my $context = $options->{context};
119 my $handler = $associations->{$context} if $context;
120 return $handler if defined $handler;
121
122 for my $context (keys %{ $associations }) {
123 if ($self->{contexts}->{$context}->()) {
124 return $associations->{$context};
125 }
126 }
127 }
128 }
129 }
130 }
131
132 sub fey {
133 App::Fey->new(ref $_[0] ? $_[0] : {})->launch(@_);
134 }