File Coverage

lib/Kephra/Document/Data.pm
Criterion Covered Total %
statement 6 180 3.3
branch 0 114 0.0
condition 0 24 0.0
subroutine 2 49 4.0
pod 0 43 0.0
total 8 410 1.9


line stmt bran cond sub pod time code
1             package Kephra::Document::Data;
2             our $VERSION = '0.08';
3            
4 1     1   1211 use strict;
  1         3  
  1         36  
5 1     1   5 use warnings;
  1         2  
  1         2757  
6            
7             # global values
8             my %values; # global doc values
9 0     0 0   sub values { \%values }
10 0 0   0 0   sub get_value { $values{$_[0]} if defined $values{$_[0]} }
11 0 0   0 0   sub set_value { $values{$_[0]} = $_[1] if defined $_[1] }
12 0     0 0   sub inc_value { $values{$_[0]}++ }
13 0     0 0   sub dec_value { $values{$_[0]}-- }
14 0 0   0 0   sub del_value { delete $values{$_[0]} if defined $values{$_[0]}}
15            
16             # values per dos
17             my @attributes; # data per doc for all open docs
18             my $current_attr; # data of current doc
19             my $current_nr = 0;
20             my $previous_nr = 0;
21            
22             # global attr functions
23 0     0     sub _attributes { \@attributes }
24 0     0     sub _values { \%values }
25 0     0     sub _hash { $attributes[$_[0]] }
26             sub _ep {
27 0     0     my $nr = valid_or_current_doc_nr($_[0]);
28 0 0         return if $nr < 0;
29 0           my $ep = $attributes[$nr]{ep_ref};
30 0 0         $ep if Kephra::App::EditPanel::is($ep);
31             }
32            
33 0     0 0   sub count { @attributes }
34 0     0 0   sub last_nr { $#attributes }
35 0     0 0   sub previous_nr { $previous_nr }
36 0     0 0   sub current_nr { $current_nr }
37             sub next_nr {
38 0     0 0   my $inc = shift;
39 0 0 0       return unless defined $inc and $inc;
40 0           my $base = shift;
41 0 0         $base = current_nr() unless defined $base;
42 0           my $last_nr = last_nr();
43 0           my $nr = $base + $inc;
44 0 0         $nr += $last_nr+1 if $nr < 0;
45 0 0         $nr -= $last_nr+1 if $nr > $last_nr;
46 0           return validate_doc_nr($nr);
47             }
48 0     0 0   sub all_nr { [0..last_nr()] }
49 0     0 0   sub get_previous_nr { $previous_nr }
50 0 0   0 0   sub set_previous_nr { $previous_nr = $_[0] if defined $_[0] }
51 0     0 0   sub get_current_nr { $current_nr }
52             sub set_current_nr {
53 0 0 0 0 0   $current_nr = $_[0] if defined $_[0] and validate_doc_nr($_[0]) > -1;
54 0           $current_attr = $attributes[$current_nr];
55 0           Kephra::App::EditPanel::_set_ref( _ep($current_nr) );
56 0           my $fconf = Kephra::File::_config();
57 0 0         $fconf->{current}{directory} = get_attribute('directory', $current_nr)
58             if ref $fconf;
59             }
60             sub validate_doc_nr {
61 0     0 0   my $nr = shift;
62 0 0         return -1 unless defined $nr;
63 0 0         return -1 unless $nr eq int $nr;
64 0 0         $nr = exists $attributes[$nr] ? $nr : -1;
65             }
66             sub valid_or_current_doc_nr {
67 0     0 0   my $nr = validate_doc_nr(shift);
68 0 0         $nr == -1 ? current_nr() : $nr;
69             }
70             sub create_slot {
71 0     0 0   my $nr = shift;
72 0           $attributes[$_+1] = $attributes[$_] for reverse $nr .. last_nr();
73 0           $attributes[$nr] = {};
74 0 0         set_current_nr($current_nr+1) if $current_nr >= $nr;
75 0 0         $previous_nr++ if $previous_nr >= $nr;
76             }
77             sub empty_slot {
78 0     0 0   my $nr = shift;
79 0 0 0       return if $nr < 0 or exists $attributes[$nr];
80 0           $attributes[$nr] = {}
81             }
82             sub delete_slot {
83 0     0 0   my $nr = validate_doc_nr(shift);
84 0 0         return if $nr < 0;
85 0           splice @attributes, $nr, 1;
86             }
87            
88             # generic attr data accessors on any value and any doc
89             sub get_attribute {
90 0     0 0   my $attr = shift;
91 0 0 0       return unless defined $attr or $attr;
92 0           my $nr = shift;
93 0 0         $nr = defined $nr ? validate_doc_nr($nr) : current_nr();
94 0 0         return if $nr < 0;
95 0 0         $attributes[ $nr ]{ $attr } if defined $attributes[ $nr ]{ $attr };
96             }
97            
98             sub set_attribute {
99 0     0 0   my $attr = shift;
100 0           my $value = shift;
101 0 0         return unless defined $value;
102 0           my $nr = shift;
103 0 0         $nr = defined $nr ? validate_doc_nr($nr) : current_nr();
104 0 0         return if $nr < 0;
105 0           $attributes[ $nr ]{ $attr } = $value;
106 0           $value;
107             }
108            
109             sub set_all_attributes { # all attr of one doc
110 0     0 0   my $attr = shift;
111 0           my $nr = validate_doc_nr(shift);
112 0 0 0       return if $nr < 0 or ref $attr ne 'HASH';
113 0           $attributes[ $nr ] = $attr;
114             }
115             # shortcut accessors just for current doc and many values
116             sub attributes {
117 0     0 0   my $params = shift;
118 0           my $nr = validate_doc_nr(shift);
119 0 0         return if $nr < 0;
120 0           my $attr = $attributes[$nr];
121 0 0         if (ref $params eq 'ARRAY') {
    0          
122 0           my @result;
123 0           push @result, $attr->{ $_ } for @$params;
124 0           return \@result;
125             }
126             elsif (ref $params eq 'HASH') {
127 0           $attr->{$_} = $params->{$_} for keys %$params;
128             }
129             }
130             # shortcut accessors just for current doc and one value
131             sub attr {
132 0 0   0 0   if (defined $_[1]){ $current_attr->{$_[0]} = $_[1]}
  0            
133 0           else { $current_attr->{$_[0]} }
134             }
135            
136             # specific data (attribute) accessors
137 0     0 0   sub first_name { get_attribute('firstname', $_[0]) }
138 0     0 0   sub file_name { get_attribute('file_name', $_[0]) }
139 0 0   0 0   sub file_path { defined $_[0] ? set_file_path($_[0]) : get_file_path() }
140 0     0 0   sub get_file_path { get_attribute('file_path', $_[0]) }
141             sub set_file_path {
142 0     0 0   my ( $file_path, $doc_nr ) = @_;
143 0           $doc_nr = valid_or_current_doc_nr($doc_nr);
144 0           set_attribute('file_path', $file_path, $doc_nr);
145 0           dissect_path( $file_path, $doc_nr );
146             }
147            
148             sub dissect_path {
149 0     0 0   my ($file_path, $doc_nr) = @_;
150 0           $doc_nr = validate_doc_nr($doc_nr);
151 0 0         return if $doc_nr < 0;
152 0           my $attr = $attributes[$doc_nr];
153 0           my ($volume, $directories, $file) = File::Spec->splitpath( $file_path );
154 0 0         $directories = $volume.$directories if $volume;
155 0           $attr->{directory} = $directories;
156 0           $attr->{file_name} = $file;
157            
158 0 0         if ( length($file) > 0 ) {
159 0           my @filenameparts = split /\./, $file ;
160 0 0         $attr->{ending} = pop @filenameparts if @filenameparts > 1;
161 0           $attr->{firstname}= join '.', @filenameparts;
162             }
163             }
164            
165             sub all_file_pathes {
166 0     0 0   my @pathes;
167 0           push @pathes, $_->{file_path} for @attributes;
168 0           return \@pathes;
169             }
170             sub all_file_names {
171 0     0 0   my @names;
172 0           $names[$_] = $_->{file_name} for @attributes;
173 0           return \@names;
174             }
175            
176             sub nr_from_file_path {
177 0     0 0   my $given_path = shift;
178 0 0         return -1 unless $given_path;
179 0           for ( 0 .. $#attributes ) {
180 0 0 0       if (defined $attributes[$_]{'file_path'}
181             and $attributes[$_]{'file_path'} eq $given_path) {
182 0           return $_;
183             }
184             }
185 0           return -1;
186             }
187            
188 0 0   0 0   sub file_already_open { 1 if nr_from_file_path(shift) > -1 }
189             sub cursor_pos {
190 0 0   0 0   $attributes[$current_nr]{cursor_pos} if $values{loaded};
191             }
192             sub nr_from_ep {
193 0     0 0   my $ep = shift;
194 0           for (@{all_nr()}) {
  0            
195 0 0         return $_ if $ep eq _ep($_);
196             }
197 0           return -1;
198             }
199             sub get_all_ep {
200 0     0 0   my @ep;
201 0           for (@{all_nr()}) {
  0            
202 0           my $ep = _ep($_);
203 0 0         push @ep, $ep if $ep;
204             }
205 0           \@ep;
206             }
207            
208             # more complex operations
209             sub set_missing_attributes_to_default {
210 0     0 0   my ($nr, $file) = @_;
211 0           $nr = validate_doc_nr($nr);
212 0 0         return if $nr < 0;
213 0 0         $file = get_file_path($nr) unless defined $file;
214 0           my $default = Kephra::File::_config()->{defaultsettings};
215             }
216            
217             sub set_attributes_to_default {
218 0     0 0   my ($nr, $file) = @_;
219 0           $nr = validate_doc_nr($nr);
220 0 0         return if $nr < 0;
221 0           my $config = Kephra::File::_config()->{defaultsettings};
222 0 0         return unless ref $config eq 'HASH';
223 0 0         $file = get_file_path($nr) unless defined $file;
224 0           my $attr = {
225             'edit_pos' => -1,
226             'ep_ref' => _ep($nr),
227             'file_path' => $file,
228             };
229 0 0 0       my $default = (defined $file and -e $file) ? $config->{open} : $config->{new};
230             $attr->{$_} = $default->{$_}
231 0           for qw(EOL codepage cursor_pos readonly syntaxmode tab_size tab_use);
232 0           set_all_attributes($attr, $nr);
233 0           dissect_path($file, $nr);
234 0 0         set_current_nr($nr) if $nr == current_nr();
235             }
236            
237             sub evaluate_attributes {
238 0     0 0   my $doc_nr = validate_doc_nr(shift);
239 0 0         return if $doc_nr < 0;
240 0           my $config = Kephra::File::_config();
241 0           my $attr = $attributes[$doc_nr];
242 0           my $ep = Kephra::App::EditPanel::_ref();
243            
244 0           Kephra::EventTable::freeze('document.text.change');
245             Kephra::Document::Property::set( {$_ => $attr->{$_} } )
246 0           for qw(codepage tab_use tab_size EOL readonly syntaxmode);
247 0           Kephra::EventTable::thaw('document.text.change');
248            
249             # setting selection and caret position
250 0 0 0       if ($attr->{selstart} and $attr->{selstart}) {
251 0 0         $attr->{cursor_pos} < $attr->{selend}
252             ? $ep->SetSelection( $attr->{selend},$attr->{selstart})
253             : $ep->SetSelection( $attr->{selstart},$attr->{selend});
254             }
255 0           else { $ep->GotoPos( $attr->{cursor_pos} ) }
256 0 0         if ($config->{open}{in_current_dir}){
257 0 0         $config->{current}{directory} = $attr->{directory}
258             if $attr->{directory};
259             }
260 0           else { $config->{current}{directory} = '' }
261 0           Kephra::App::EditPanel::set_word_chars($ep);
262 0 0         Kephra::App::EditPanel::Indicator::paint_bracelight($ep)
263             if Kephra::App::EditPanel::Indicator::bracelight_visible();
264 0           Kephra::App::EditPanel::Margin::autosize_line_number();
265 0           Kephra::App::EditPanel::Fold::restore($doc_nr);
266 0           Kephra::App::StatusBar::refresh_cursor();
267 0           Kephra::Edit::Marker::restore($doc_nr);
268 0           Kephra::Edit::_let_caret_visible();
269             }
270            
271             sub update_attributes { # was named save_properties
272 0     0 0   my $doc_nr = valid_or_current_doc_nr(shift);
273 0 0         return if $doc_nr < 0;
274 0           my $attr = _hash($doc_nr);
275 0           my $ep = _ep($doc_nr);
276 0           $attr->{cursor_pos}= $ep->GetCurrentPos;
277 0           $attr->{selstart} = $ep->GetSelectionStart;
278 0           $attr->{selend} = $ep->GetSelectionEnd;
279 0           Kephra::App::EditPanel::Fold::store($doc_nr);
280 0           Kephra::Edit::Marker::store($doc_nr);
281             }
282            
283             1;
284            
285             =head1 NAME
286            
287             Kephra::Document::Data - API for data assotiated with opened documents
288            
289             =head1 DESCRIPTION
290            
291             =cut