Hello Nobumi,
On Dec 29, 2010, at 9:33 PM, Nobumi Iyanaga wrote:
> Instead of replying to them and asking you more questions, I think I would learn more, if I try to write more macros, and ask you questions about them.
That's a nice strategy ;-)
> Here is another essay: it adds at the beginning of each line (of the main body text) the line number followed by a tab.
>
> ## add_line_numbers ##
>
> $doc = Document.active
>
> $sels = Array.new
> $sels = $doc.text.findAll '^', 'E', '-am'
>
> $tab = "\t"
> $i = $sels.count
> $num = ''
> foreach $sel in reversed $sels
> $loc = $sel.location
> $num = "$i$tab"
> $num = Cast to string $num
> $sel.text.insertAtIndex $loc, $num
> $i = $i - 1
> end
>
> ## end of macro ##
>
> I tried this macro, because it "translates" somehow the pattern of the most common macros that we used to write for Classic Nisus Writer, that is:
> 1. Find locations of strings matching some pattern with a regex search;
> 2. visit in a loop all the found strings (with "SetSelect" in the Classic Nisus Writer macro), making some change(s) to each one.
>
> This seems to work as expected. The most convenient thing here is the line:
> $sels = $doc.text.findAll '^', 'E', '-am'
> because it makes in a single line an array of all the "selectedTexts" which can be visited in the following loop. And this is very fast, because, I thing, it works in the variable (this would be the advantage of the "reference semantics"...??).
I think it is fast because findAll command does not create actual (real) selections. On the other hand,
Find All '^', 'E'
does not work because you cannot create more than a single zero-width selection.
> However, when I tried to modify this macro, so that when there is a selection of several lines (the selection must begin either at the beginning of the body text, or just after a return character...), it would add line numbers only to these lines (from 1 to n...), I am stumbled because of many problems. I tried to write something like this:
>
> $sel = TextSelection.active
> $sel_range = $sel.range
> $sel_location = $sel_range.location
> $if_slection_at_zero = false
> if $sel.length
> if $sel_location == 0
> Find All '^(.|\n)', 'Es', '-am'
> $sels = $doc.textSelections
> # exit $sels.count
> $if_slection_at_zero = true
> else
> $previous_char = $the_text.characterAtIndex ($sel_location - 1)
> if $previous_char == 10
> Find All '^', 'Es', '-am'
> $sels = $doc.textSelections
> # exit $sels.count
> else
> exit 'The selection should be done on whole lines...'
> end
> end
> else
> ...
>
> My main problem is that the value of "$sels.count" cannot be what I expect (for example, when I select two or more lines in the middle of the document, the value of "$sels.count" is 1, instead of 2 or more...).
There is another problem. Find All '^(.|\n)', 'Es', '-am' will select two or more consecutive '^\n' (empty paragraphs) as a single selection. Probably you could solve this problem by calculating the length of selections but that would make the macro complicated.
Then, you can use containsSelection command to know which paragraph starts got by
$doc.text.findAll '^', 'E', '-am'
are contained in selections you made. Something like this...
### begin macro ###
$doc = Document.active
$sels = $doc.textSelections
if ! $sels.firstValue.length # i.e. $sels[0].length
exit 'There is no visible selection, exiting...'
end
$paraStarts = $doc.text.findAll '^', 'E', '-am'
foreach $i, $start in reversed $paraStarts
$contained = false
foreach $sel in $sels
if $sel.containsSelection $start
$contained = true
break # you don't need testing the remaining values of $sels
end
end
# if $contained remains false after testing $start against all values of $sels
if $contained == false
$paraStarts.removeValueAtIndex $i
end
end
if ! $paraStarts.count
exit 'No paragraph start in selection(s), exit...'
end
$tab = Cast to String "\t"
foreach $i, $start in reversed $paraStarts
$num = $i + 1 # $i: index number
$num &= $tab
$start.text.insertAtIndex $start.location, $num
end
### end macro ###
As you see this is a question of how to do find (or replace) in selection without creating an actual selection. Another idea is to examine subtexts of the selections.
### begin macro ###
$doc = Document.active
$sels = $doc.textSelections
if ! $sels.firstValue.length # i.e. $sels[0].length
exit 'There is no visible selection, exiting...'
end
$paraStarts = Array.new
foreach $sel in $sels
$founds = $sel.subtext.findAll '^', 'E' # "where" argument does not work for subtext
foreach $found in $founds
if $found.text.documentContentType == 'body' # it may be, for example, a table cell
$range = Range.new $found.location + $sel.location, 0
$start = TextSelection.new $sel.text, $range
$paraStarts.appendValue $start
end
end
end
# the rest is the same
$tab = Cast to String "\t"
foreach $i, $start in reversed $paraStarts
$num = $i + 1 # $i: index number
$num &= $tab
$start.text.insertAtIndex $start.location, $num
end
### end macro ###
Kino
|