Concatenating documents

So, I’ve been taking notes via OmniOutliner on a daily basis, organizing one week’s worth of notes into a file. Is there a way to easily concatenate a whole bunch of them into one monolithic document? I’ve got over a year’s worth of notes that I’m interested in combining into one document.

Maybe this works for you. This script merges currently opened OmniOutliner documents.

Code:

-- unlocked2412
-- V0.02
--This script merges currently opened OmniOutliner documents.

tell application "OmniOutliner"
	tell every document
		set refRows to a reference to (every child)
	end tell
	set mergedDocument to make new document with properties {name:"Merged Document"}
	duplicate refRows to end of every row of mergedDocument
end tell
1 Like

Thanks for doing this! I just tried this, and I got an interesting outcome. For each top-level row, everything and its child row was included as expected. But it looks like it then iterated through each child row and copied those as top-level rows in the merged document.

You’re welcome, @omnifocuser

You’re right. I updated the code. Tell me if it works for you.

Tell me if it works for you

Thanks! It does now!

A shorter version:

tell application "OmniOutliner"
	duplicate documents's rows to end of (make new document)'s rows
end tell

This seems to bring over graphics better if you have any in your notes.

SG

2 Likes

I’ve started to take a serious look at switching my nots to a monolithic document, and I’ve found one thing missing in your merge script. I often embed audio clips (of meetings) in my outline files and occasionally attach other files like images. Is there a way to get them included in the merged document?

I looked into this and I think I found a solution. Tell me if it works for you, @omnifocuser.

Code:

-- unlocked2412
-- V0.02
-- This script merges currently open OO documents

on run
	tell application "OmniOutliner"
		set listA to my concat(every row of every document)
		set ooDoc to (make new document with properties {name:"MergedDocument"})
		set applyDup to |λ|(ooDoc) of my curry(dupRows)
		my map(applyDup, my concat(every child of every document))
		set listB to every row of ooDoc
		my zipWith(dupAttachments, listA, listB)
	end tell
end run

on dupRows(destDoc, anItem)
	tell application "OmniOutliner"
		duplicate anItem to end of every child of destDoc
	end tell
end dupRows

on dupAttachments(rowA, rowB)
	tell application "OmniOutliner"
		try
			duplicate every attachment of rich text of cell 1 of rowA to end of every attachment of rich text of cell 1 of rowB
		end try
	end tell
end dupAttachments

-- GENERIC FUNCTIONS ---------------------------------------------------------

-- concat :: [[a]] -> [a] | [String] -> String
on concat(xs)
	if length of xs > 0 and class of (item 1 of xs) is string then
		set acc to ""
	else
		set acc to {}
	end if
	repeat with i from 1 to length of xs
		set acc to acc & item i of xs
	end repeat
	acc
end concat

-- curry :: (Script|Handler) -> Script
on curry(f)
	script
		on |λ|(a)
			script
				on |λ|(b)
					|λ|(a, b) of mReturn(f)
				end |λ|
			end script
		end |λ|
	end script
end curry

-- map :: (a -> b) -> [a] -> [b]
on map(f, xs)
	tell mReturn(f)
		set lng to length of xs
		set lst to {}
		repeat with i from 1 to lng
			set end of lst to |λ|(item i of xs, i, xs)
		end repeat
		return lst
	end tell
end map

-- min :: Ord a => a -> a -> a
on min(x, y)
	if y < x then
		y
	else
		x
	end if
end min

-- zipWith :: (a -> b -> c) -> [a] -> [b] -> [c]
on zipWith(f, xs, ys)
	set lng to min(length of xs, length of ys)
	set lst to {}
	tell mReturn(f)
		repeat with i from 1 to lng
			set end of lst to |λ|(item i of xs, item i of ys)
		end repeat
		return lst
	end tell
end zipWith

-- Lift 2nd class handler function into 1st class script wrapper 
-- mReturn :: Handler -> Script
on mReturn(f)
	if class of f is script then
		f
	else
		script
			property |λ| : f
		end script
	end if
end mReturn
1 Like

Based on draft8 advice, I updated the code. It now preserves outline structure.