From ac62a4cc4a1881277c1ad9f11db65f8d0faaf0e8 Mon Sep 17 00:00:00 2001 From: Gerhard Gonter <ggonter@gmail.com> Date: Wed, 1 Jan 2014 00:29:08 +0100 Subject: [PATCH] converting content lines in parsend and array format back and forth seem to work now --- perl/Gnome-Tomboy/lib/Tomboy/Note/Simple.pm | 310 ++++++++++++++++++-- perl/Gnome-Tomboy/s1.pl | 54 +++- 2 files changed, 335 insertions(+), 29 deletions(-) diff --git a/perl/Gnome-Tomboy/lib/Tomboy/Note/Simple.pm b/perl/Gnome-Tomboy/lib/Tomboy/Note/Simple.pm index 048bc7f..a1bb0e3 100755 --- a/perl/Gnome-Tomboy/lib/Tomboy/Note/Simple.pm +++ b/perl/Gnome-Tomboy/lib/Tomboy/Note/Simple.pm @@ -4,10 +4,14 @@ package Tomboy::Note::Simple; =head1 NAME - Tomboy::Note::Simple; + Tomboy::Note::Simple =head1 SYNOPSIS + my $note= new Tomboy::Note::Simple (options => values); + +=head2 parsing + # version 1 my $n1= parse Tomboy::Note::Simple ($note_fnm); @@ -19,7 +23,28 @@ package Tomboy::Note::Simple; Simple abstraction for notes written with Gnome's Tomboy. The script uses XML::Parser in Tree style and uses it's parse -tree as the note's content datastructure. +tree as the note's content datastructure (stored in "text"). + +=head1 BUGS + +This module consists of originally two different ones, they are not +completely consistent. The difference is how the content is stored. + +In a .note file, contents looks like this: + + <text xml:space="preserve"><note-content version="0.1">title line + content line2 + ... + last content last</note-content></text> + + * Parser: based on XML::Parser, stores contents in + @nc= @{$note->{'text'}->[2]} which represents the the <note-content> + element, the first text-part starts at $nc[2] + + * Generator: contents (the stuff *in* the "note-content" element) + is put into "lines" the first line, however, is stored in 'title'. + +That should be further unified. =cut @@ -30,40 +55,69 @@ use JSON; use Data::Dumper; $Data::Dumper::Indent= 1; +use Tomboy; +use Util::XML_Parser_Tree; + my %fields= ( 'title' => {}, 'last-change-date' => {}, 'last-metadata-change-date' => {}, 'create-date' => {}, - 'cursor-position' => {}, - 'selection-bound-position' => {}, - 'width' => {}, - 'height' => {}, - 'x' => {}, - 'y' => {}, - 'open-on-startup' => {}, + 'cursor-position' => { 'default' => 0 }, + 'selection-bound-position' => { 'default' => -1, 'supress' => 1 }, + 'width' => { 'default' => 450 }, + 'height' => { 'default' => 360 }, + 'x' => { 'default' => 0 }, + 'y' => { 'default' => 0 }, + 'open-on-startup' => { 'default' => 'False' }, ); +my @fields_date= qw( last-change-date last-metadata-change-date create-date ); +my @fields_default1= qw( cursor-position selection-bound-position width height x y ); +my @fields_default2= qw( open-on-startup ); +my @fields_seq1= (@fields_date, @fields_default1); +my @fields_seq2= (@fields_default2); + +my ($s_text, $e_text)= ('<text xml:space="preserve">', '</text>'); +my ($s_note_content, $e_note_content)= ('<note-content version="0.1">', '</note-content>'); + sub new { my $class= shift; - my %par= @_; - - my $note= {}; - bless $note, $class; - foreach my $par (keys %par) + my $title= 'New Note ' . Tomboy::ts_ISO (); + my $note= { - $note->{$par}= $par{$par}; - } + 'lines' => [ $title ], + 'title' => $title, + }; + foreach my $f (@fields_date) { $note->{$f}= Tomboy::ts_ISO() } + foreach my $f (@fields_default1) { $note->{$f}= $fields{'default'} } + + bless $note, $class; + $note->set (@_); $note; } +sub set +{ + my $note= shift; + my %par= @_; + + foreach my $par (keys %par) { $note->{$par}= $par{$par} } + 1; +} + +=head1 Group1: Parsing + +=cut + sub empty_text { my $note= shift; + my $title= shift || 'empty text'; $note->{'text'}= [ { @@ -75,9 +129,11 @@ sub empty_text 'version' => '0.1' }, 0, - 'empty text' + $title, ] ]; + $note->{'title'}= $title; + $note->{'lines'}= [ $title ]; 1; } @@ -105,8 +161,16 @@ sub parse my $p= new XML::Parser (Style => 'Tree'); # print "p: ", Dumper ($p); - my $l1= $p->parsefile($fnm, ErrorContext => 3); + my $l1; + eval { $l1= $p->parsefile($fnm, ErrorContext => 3) }; + if ($@) + { + print "parsefile failed fnm=[$fnm]:\n", $@, "\n"; + return undef; + } + # print "l1: ", Dumper ($l1); + # my $s_l1= Util::XML_Parser_Tree::to_string (@$l1); print "s_l1=[$s_l1]\n"; my ($tag, $nc, @rest)= @$l1; # print "res: ", Dumper ($res); @@ -145,9 +209,18 @@ sub parse if ($t1 eq '0') {} # skip text elsif ($t1 eq 'tag') { - # print "t2: [$t2]\n"; - push (@{$note->{'tags'}}, $t2->[2]); -# ZZZ + my $tag= $t2->[2]; + push (@{$note->{'tags'}}, $tag); + + if ($tag eq 'system:template') + { + $note->{'is_template'}= 1; + } + elsif ($tag =~ m#system:notebook:(.+)#) + { + $note->{'notebook'}= $1; + } + # TODO: maybe there other tags as well... } } } @@ -164,7 +237,186 @@ sub parse $note; } -1; +=head1 Group 1+2: glue + +=cut + +sub text_to_lines +{ + my $note= shift; + + my $x= $note->{'text'}; + + # print "x: ", Dumper($x); + + my $nc= $x->[2]; + # print "nc: ", Dumper($nc); + shift (@$nc); # remove the text-element's attributes + my $s= Util::XML_Parser_Tree::to_string (@$nc); + + # split drops the new lines at the end, so we need to go the extra mile + my $cnt= length ($1) if ($s=~ s#(\n+)$##); + my @s= split ("\n", $s); + for (my $i= 1; $i < $cnt; $i++) { push (@s, '') } + + # print "complete string: [$s]\n"; + # print "s: ", Dumper (\@s); + # print "cnt: ", $cnt, "\n"; + + my $title= $s[0]; + # TODO: compare existing title + $note->{'title'}= $title unless ($note->{'title'}); + $note->{'lines'}= \@s; + + # ($title, @s); + 1; +} + +sub parse_lines +{ + my $note= shift; + + # print "text: ", Dumper ($note->{'text'}); + my @lines= @{$note->{'lines'}}; + my $start= join ('', $s_text, $s_note_content, shift (@lines)); + my $x= parse_string (join ("\n", $start, @lines, join ('', $e_note_content, $e_text))); + $note->{'text'}= $x->[1]; +} + +sub parse_string +{ + my $str= shift; + + # print "str=[$str]\n"; + my $p= new XML::Parser (Style => 'Tree'); + # print "p: ", Dumper ($p); + my $l1; + eval { $l1= $p->parsestring($str, ErrorContext => 3) }; + if ($@) + { + print "parsestring failed str=[$str]:\n", $@, "\n"; + return undef; + } + # print "l1: ", Dumper ($l1); + $l1; +} + +=head1 Group 2: text generator + +=cut + +sub add_lines +{ + my $note= shift; + + foreach my $line (@_) + { + my @lines= split (/\n/, $line); + @lines= ('') unless (@lines); + # print "line=[$line] lines: ", main::Dumper (\@lines); + push (@{$note->{'lines'}}, @lines); + } + + $note->{'e_updated'}= time(); +} + +sub save +{ + my $note= shift; + my $out_dir= shift; + my $fnm_out= shift; + + my ($title, $uuid, $ts_updated, $ts_md_updated, $ts_created, $e_updated, $lines, $is_template, $nb_name)= + map { $note->{$_} } qw(title uuid last-change-date last-metadata-change-date create-date e_updated lines is_template notebook); + + # sanitize data + $note->{'uuid'}= $uuid= Tomboy::get_uuid() unless ($uuid); + $note->{'title'}= $title= $uuid unless ($title); + + if ($e_updated) + { + $note->{'last-metadata-change-date'}= $ts_md_updated= + $note->{'last-change-date'}= $ts_updated= Tomboy::ts_ISO($e_updated); + } + + $note->{'create-date'}= $ts_created= $ts_updated unless ($ts_created); + +# print "tags: ", Dumper ($note->{'tags'}); + my @tags= (); + push (@tags, 'system:template') if ($is_template); + push (@tags, 'system:notebook:'. $nb_name) if ($nb_name); + + unless (defined ($fnm_out)) + { + $fnm_out= $out_dir if ($out_dir); + $fnm_out.= $uuid . '.note'; + } + + unless (open (FO, '>:utf8', $fnm_out)) + { + print STDERR "can't write to [$fnm_out]\n"; + return undef; + } + + print "writing note [$fnm_out]: [$title]\n"; # TODO: if verbose + + print FO chr(65279); # write a BOM, Tomboy seems to like that + print FO <<EOX; +<?xml version="1.0" encoding="utf-8"?> +<note version="0.3" xmlns:link="http://beatniksoftware.com/tomboy/link" xmlns:size="http://beatniksoftware.com/tomboy/size" xmlns="http://beatniksoftware.com/tomboy"> +EOX + print FO ' <title>'. Util::XML_Parser_Tree::tlt($title) ."</title>\n"; + print FO ' ', $s_text, $s_note_content; + + foreach my $line (@$lines) + { + print FO $line, "\n"; + } + + print FO $e_note_content, $e_text, "\n"; + + foreach my $f (@fields_seq1) + { + print_attribute (*FO, $note, $f); + } + + if (@tags) + { + print FO " <tags>\n"; + foreach my $tag (@tags) { print FO " <tag>", $tag, "</tag>\n"; } + print FO " </tags>\n"; + } + + foreach my $f (@fields_seq2) + { + print_attribute (*FO, $note, $f); + } + + print FO "</note>"; # No newline at end of file, that's how Tomboy does that ... + close (FO); + + $fnm_out; +} + +sub print_attribute +{ + local *F= shift; + my $n= shift; + my $f= shift; + + my $a= $n->{$f}; + unless (defined ($a)) + { + my $x= $fields{$f}; + return if (exists ($x->{'supress'})); # supress the default for that one + my $b; + if (exists ($x->{'default'})) { $b= $x->{'default'} } + # TODO: elsif exists function .... + $n->{$f}= $a= $b if (defined ($b)); + } + + print F ' <', $f, '>', $a, '</', $f, ">\n"; +} __END__ @@ -174,7 +426,19 @@ __END__ =head1 BUGS -* XML::Parser throws exceptions, these are currently not handled. +* XML::Parser throws exceptions, these are currently not handled well. =cut + <tags> + <tag>system:notebook:Kalender 2014</tag> + </tags> + +Template: + <tags> + <tag>system:template</tag> + <tag>system:notebook:Kalender 2014</tag> + </tags> + +1; + diff --git a/perl/Gnome-Tomboy/s1.pl b/perl/Gnome-Tomboy/s1.pl index 8afca80..81c9bde 100755 --- a/perl/Gnome-Tomboy/s1.pl +++ b/perl/Gnome-Tomboy/s1.pl @@ -1,5 +1,15 @@ #!/usr/bin/perl +=head1 NAME + + s1.pl + +=head1 DESCRIPTION + +Script to play with Tomboy::Note::Simple for testing. + +=cut + use strict; use lib 'lib'; @@ -9,17 +19,49 @@ use Tomboy::Note::Simple; use Data::Dumper; $Data::Dumper::Indent= 1; -my $note_fnm= shift (@ARGV); +die "no note filename specified" unless (@ARGV); + +open (FO, '>:utf8', 'do_verify.sh'); +while (my $arg= shift (@ARGV)) +{ + process_note ($arg); +} +close (FO); + +exit (0); + +sub process_note +{ + my $note_fnm= shift; -die "no note filename specified" unless ($note_fnm); +print '='x90, "\n"; +print "process_note note_fnm=[$note_fnm]\n"; # V1: -# my $n= parse Tomboy::Note::Simple ($note_fnm); +my $n= parse Tomboy::Note::Simple ($note_fnm); # V2: -my $n= new Tomboy::Note::Simple; $n->parse ($note_fnm); +# my $n= new Tomboy::Note::Simple; $n->parse ($note_fnm); -print "n: ", Dumper ($n); +$n->text_to_lines (); +# print "lines: ", Dumper ($n->{'lines'}); +$n->parse_lines (); +# print "n: ", Dumper ($n); + +my $saved= $n->save(); + +print "saved=[$saved]\n"; +my @cmd= ('diff', '-u', $note_fnm, $saved); +print join (' ', @cmd), "\n"; +my $rc= system (@cmd); +print "rc=[$rc]\n\n"; + +if ($rc != 0) +{ + print FO join (' ', @cmd), "\n"; +} + + $rc; +} -exit (0); -- GitLab