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
|