List with TOC entries
List with TOC entries
I wonder if somebody can help with the following:
Think of a document made of a series of notes. Each note may have one or several paragraphs. Each note is preceded by a heading, and the headings are made TOC entries.
With "Show TOC in Navigator" on, clicking the main text at any location will highlight the corresponding heading in the navigator. Is it possible to obtain the text of the heading through a macro?
A related question: Clicking the navigator, then doing Select All and Copy puts a list of all headings on the clipboard. Can that list be created by a macro, even if the insertion is in the main text?
Think of a document made of a series of notes. Each note may have one or several paragraphs. Each note is preceded by a heading, and the headings are made TOC entries.
With "Show TOC in Navigator" on, clicking the main text at any location will highlight the corresponding heading in the navigator. Is it possible to obtain the text of the heading through a macro?
A related question: Clicking the navigator, then doing Select All and Copy puts a list of all headings on the clipboard. Can that list be created by a macro, even if the insertion is in the main text?
Re: List with TOC entries
For the first problem you can get the text of the paragraph of your current location with code like this:
For the second problem, I'm going to assume that the headings are marked with a style called "Heading". In that case code like this will give you an array with all the heading texts.
If you don't have a heading style, it's still possible to collect all the text marked for TOC via macro, but things are a bit more complicated.
Code: Select all
$sel = TextSelection.active
$paraRange = $sel.text.rangeOfParagraphAtIndex $sel.location
$paraText = $sel.text.subtextInRange $paraRange
prompt $paraText
Code: Select all
$doc = Document.active
$headingStyle = $doc.styleWithName "Heading"
$headingSels = $doc.text.findAll $headingStyle
$headingTexts = $headingSels.arrayByMakingValuesDoCommand "subtext"
prompt $headingTexts
philip
Re: List with TOC entries
G'day, js, Philip et al
As long as the cursor is not in a note heading, there is a supplied macro that will take you from anywhere in a note to its heading:–
Tools > Table of Contents > Select Previous in TOC.
Being selected, the text of the heading can then be copied or otherwise manipulated as required.
If the cursor is already in a note heading, the macro will take you to the heading of the previous note.
Cheers,
Adrian
As long as the cursor is not in a note heading, there is a supplied macro that will take you from anywhere in a note to its heading:–
Tools > Table of Contents > Select Previous in TOC.
Being selected, the text of the heading can then be copied or otherwise manipulated as required.
If the cursor is already in a note heading, the macro will take you to the heading of the previous note.
Cheers,
Adrian
MacBook Pro (M1 Pro, 2021)
macOS Ventura
Nisus Writer user since 1996
macOS Ventura
Nisus Writer user since 1996
Re: List with TOC entries
Upon seeing adryan's answer, I realised that I misunderstood the (first) question. To do that you have several possibilities. You could use the command adryan mentions and save and restore the selection. If you want to do this directly via the macro language, you have to use a (backwards) "Kino loop". The code for that would look something like this:
If all the TOC marked bits have the same style applied you could write a simpler macro using "Find".
Code: Select all
$doc = Document.active
$loc = $doc.textSelection.location
while $loc >= 0
$range = $doc.text.rangeOfParagraphContentAtIndex($loc)
$loc = $range.location
$attrs = $doc.text.displayAttributesAtIndex $loc
if $attrs.tocLevelForStyleName($doc.activeTocStyleName) == @undefined
$loc -= 1
else
break
end
end
prompt $doc.text.subtextInRange($range)
philip
Re: List with TOC entries
Thank you very much for your help, phspaelti and adryan. May I ask two supplementary questions:
Referring to your macro:
The result (the $headingTexts) in your macro is shown in a prompt. If instead I send it to a new file, I get the text as entries of a list, separated by quotes and commas. Of course I can get rid of these by a search and replace. But isn‘t there a means of getting the Text without these separators directly?
Referring to your macro
This works fine. My ultimate ambition goes a bit further: It is to do get the $headingTexts of ALL instances of a search expression in the document. Should I write a macro that reiterates the one you offered across the whole document, collecting the headings appearing in the macros as ($doc.text.subtextInRange($range) one by one. Or would one of you code warriors know how to get all instances right from the outset?
Referring to your macro:
Code: Select all
$doc = Document.active
$headingStyle = $doc.styleWithName "Heading"
$headingSels = $doc.text.findAll $headingStyle
$headingTexts = $headingSels.arrayByMakingValuesDoCommand "subtext"
prompt $headingTexts
Referring to your macro
Code: Select all
$doc = Document.active
$loc = $doc.textSelection.location
while $loc >= 0
$range = $doc.text.rangeOfParagraphContentAtIndex($loc)
$loc = $range.location
$attrs = $doc.text.displayAttributesAtIndex $loc
if $attrs.tocLevelForStyleName($doc.activeTocStyleName) == @undefined
$loc -= 1
else
break
end
end
prompt $doc.text.subtextInRange($range)
Re: List with TOC entries
Hello js,
I ended the macro with a prompt simply for demonstration purposes. As mentioned the texts will be in a structure called an array. How you continue from there will depend on what you want to do.
As you found out, if you just print out a raw array, you will get something with lots of commas and quotes. You can join the bits of an array much more nicely like this:
The join command will glue the bits together using whatever is between the quotes (In this case nothing.)
You can use this join command in several ways. If you want the texts in a new document, you can do it like this:
Or you can put the texts on the clipboard like this:
Instead of joining them in a list, you can process the texts one at a time like this:
Okay, now from your last comment, I take it you would prefer a macro that collects the TOC without having a known style that marks them. You can use the "Kino loop" technique to do that too.
That will look like this:
If we're gonna collect the TOC from the whole file, it makes more sense to work forward. Note that here I changed things back to using rangeOfParagraphAtIndex, so we'll get the returns for each TOC item too. If you don't want that, the code could be adjusted a bit.
Hope this helps
I ended the macro with a prompt simply for demonstration purposes. As mentioned the texts will be in a structure called an array. How you continue from there will depend on what you want to do.
As you found out, if you just print out a raw array, you will get something with lots of commas and quotes. You can join the bits of an array much more nicely like this:
Code: Select all
prompt $headingTexts.join('')
You can use this join command in several ways. If you want the texts in a new document, you can do it like this:
Code: Select all
Document.newWithText $headingTexts.join('')
Code: Select all
Write Clipboard $headingTexts.join('')
Code: Select all
Foreach $headingText in $headingTexts
… do some stuff …
end
That will look like this:
Code: Select all
$doc = Document.active
$headingTexts = Array.new
$loc = 0
while $loc < $doc.text.length
$range = $doc.text.rangeOfParagraphAtIndex($loc)
$attrs = $doc.text.displayAttributesAtIndex $loc
if $attrs.tocLevelForStyleName($doc.activeTocStyleName)
$headingTexts.push $doc.text.subtextInRange($range)
end
$loc = $range.bound
end
prompt $headingTexts.join('')
Hope this helps
philip
Re: List with TOC entries
Thanks Philip for this renewed help, and explaining how to use .join(''). This is what I was hoping to get.
As to your new macro, it works well. But it does the same thing as the first one: If makes a list of all headings. That fine for finding a search word within the headings themselves. In fact if you a search in the main text, the headings which have that search word are selected by Nisus Writer, in the Navigator on the left. It‘s just that you cannot take them out. And that is what the first macro is for.
The second macro is for a different purpose: It should create a list of those headings the text of which has my search word, even if it is not contained in the heading itself. You provided a macro for doing this for a single item. That works well. But how about a complete list of those headings having my search word, even if not in the heading itself, but only in the text UNDER that heading. Sorry to sound complicated. But the aim is a very practical one: To show me all past „titles“ under which a certain search word figures.
As to your new macro, it works well. But it does the same thing as the first one: If makes a list of all headings. That fine for finding a search word within the headings themselves. In fact if you a search in the main text, the headings which have that search word are selected by Nisus Writer, in the Navigator on the left. It‘s just that you cannot take them out. And that is what the first macro is for.
The second macro is for a different purpose: It should create a list of those headings the text of which has my search word, even if it is not contained in the heading itself. You provided a macro for doing this for a single item. That works well. But how about a complete list of those headings having my search word, even if not in the heading itself, but only in the text UNDER that heading. Sorry to sound complicated. But the aim is a very practical one: To show me all past „titles“ under which a certain search word figures.
Re: List with TOC entries
Okay, so your TOC headings do all have the heading style. In that case those two macros will give the same result. In that case I'll stick with the "find $style" version, since it's simpler.js wrote:As to your new macro, it works well. But it does the same thing as the first one
And now I finally got what you want, I think. You are starting with a non-contiguous selection, and you want all the closest preceding headings to each selected bit. I'm also going to assume that you want each heading only once, even if a note contains multiple selected bits (= find hits).
And yes, you could use the earlier macro (the "backward Kino loop") inside a loop like this:
Code: Select all
foreach $sel in $doc.textSelections
… find the preceding heading …
end
- Get the selections
- Get the headings
- Walk through the two arrays in parallel, and keep advancing to match selections with preceding headings. Throw away any headings you don't need, and keep the ones you want
- That you start with a non-contiguous selection already made
- That your headings have the style name "Heading"
- That you want the output in a new file
- Attachments
-
js_ Headings_for_Selections.nwm
- (4.94 KiB) Downloaded 911 times
philip
Re: List with TOC entries
A double thank you to philip, one for the macro itself. It does exactly what I wanted. And one for his explanations, very helful to better understand the workings of Nisus macro language.