The (AppleScript) sketch below is a thought experiment – untested, and not ready for use with real data.
The issue it deals with is the non-standard (Omni-initiated, I think, and some other apps follow its lead) pattern of storing some non-outline paragraphs in an outline row as “notes”, using an XML attribute named _note
.
By default, Bike happily opens and saves OPML with these _note
attributes but doesn’t at the moment show their presence in the editor.
I’m personally not a fan of the Title + Body Paras
approach to using outliners, which I think:
- is a hangover from email
- excludes some paragraphs from outlining operations
- implies two different kinds of editor in one app
but given that it’s out there, and Bike users may well need to import existing _note
attributed OPML, here’s an experiment (not ready for use – test only with dummy data) in:
- toggling hidden
_note
attributes into visible Bike rows, prefixed with (for example)>
(for import) - toggling childless (
>
prefixed) rows, at the start of a sibling sequence, into a_note
attribute of the parental row (for export)
Really just a first experiment with the new scriptability of key:value
attributes in Bike rows, and not intended as a working tool:
Expand disclosure triangle to view AppleScript source
-- Possible approach ?
-- Not sure ...
-- EXPERIMENT ONLY – NOT READY FOR USE WITH REAL DATA
-- (I never like to share anything that uses a 'delete' method)
-- Ver 0.02
-- This cannot really be done in JXA I, I think, for lack of location specifiers
-- e.g. in `make new row at beginning of rows`
-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
-- BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-- NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
-- DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM
-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
------- TOGGLE _NOTE ATTRIBUTES ⇄ PREFIXED CHILDREN ------
on run
tell application "Bike"
set doc to front document
if exists doc then
set docRows to a reference to rows of doc
set rowNotePairs to my docRowsWithNotes(docRows)
if 0 < length of rowNotePairs then
my noteAttribsToPrefixedChildren(">", doc, rowNotePairs)
else
my prefixedChildrenToNoteAttribs(">", docRows)
end if
else
"No document open in Bike"
end if
end tell
end run
--------------------- NOTE ATTRIBUTES --------------------
-- docRowsWithNotes :: Bike Doc -> IO [(Row, String)]
on docRowsWithNotes(rowsOfDoc)
using terms from application "Bike"
tell rowsOfDoc
set noteAttribs to a reference to ¬
(attributes where name is "_note")
end tell
script go
on |λ|(xs)
if {} ≠ xs then
{item 1 of xs}
else
{}
end if
end |λ|
end script
zip(concatMap(go, container row of noteAttribs), ¬
concatMap(my identity, value of noteAttribs))
end using terms from
end docRowsWithNotes
-- noteAttribsToPrefixedChildren :: Char -> [(Row, String)] -> IO ()
on noteAttribsToPrefixedChildren(prefixChar, doc, rowNotePairs)
using terms from application "Bike"
repeat with ab in rowNotePairs
set {attribRow, attribText} to ab
--
repeat with para in paragraphs of attribText
tell doc to make new row at beginning of rows of attribRow ¬
with properties {name:prefixChar & space & para}
set attrib to (a reference to ¬
(attribute "_note" of attribRow))
if exists attrib then delete attrib
end repeat
end repeat
end using terms from
end noteAttribsToPrefixedChildren
-- prefixedChildrenToNoteAttribs :: Char -> Rows -> IO ()
on prefixedChildrenToNoteAttribs(prefixChar, docRows)
using terms from application "Bike"
set prefixedNoteRows to {}
repeat with oRow in docRows
set isParent to contains rows of oRow
if isParent then
set xs to (rows of oRow)
set lst to {}
repeat with oChild in xs
set x to oChild
if not (contains rows of x) then
set s to name of oChild
if s begins with prefixChar then
set end of lst to my drop(2, s)
set end of prefixedNoteRows to x
end if
end if
end repeat
if {} ≠ lst then
tell oRow
make attribute with properties {name:"_note", value:my unlines(lst)}
end tell
end if
end if
end repeat
set n to length of prefixedNoteRows
repeat with i from n to 1 by -1
delete item i of prefixedNoteRows
end repeat
end using terms from
end prefixedChildrenToNoteAttribs
------------------------- GENERIC ------------------------
-- concatMap :: (a -> [b]) -> [a] -> [b]
on concatMap(f, xs)
set lng to length of xs
set acc to {}
tell mReturn(f)
repeat with i from 1 to lng
set acc to acc & (|λ|(item i of xs, i, xs))
end repeat
end tell
acc
end concatMap
-- identity :: a -> a
on identity(x)
-- The argument unchanged.
x
end identity
-- min :: Ord a => a -> a -> a
on min(x, y)
if y < x then
y
else
x
end if
end min
-- mReturn :: First-class m => (a -> b) -> m (a -> b)
on mReturn(f)
-- 2nd class handler function lifted into 1st class script wrapper.
if script is class of f then
f
else
script
property |λ| : f
end script
end if
end mReturn
-- drop :: Int -> String -> String
on drop(n, xs)
if n < length of xs then
text (1 + n) thru -1 of xs
else
""
end if
end drop
-- unlines :: [String] -> String
on unlines(xs)
-- A single string formed by the intercalation
-- of a list of strings with the newline character.
set {dlm, my text item delimiters} to ¬
{my text item delimiters, linefeed}
set s to xs as text
set my text item delimiters to dlm
s
end unlines
-- zip :: [a] -> [b] -> [(a, b)]
on zip(xs, ys)
set n to min(length of xs, length of ys)
set lst to {}
repeat with i from 1 to n
set end of lst to {item i of xs, item i of ys}
end repeat
lst
end zip