Here is a rough draft of Jesse’s approach.
At the bottom of the script, you will find some options, including for:
- The file path of the target TaskPaper 3 file, and
- the name of the Reminders list to transfer.
If you don’t want it to check for successful transfer and then delete the Reminders.app copy, then edit the value of deleteReminderAfterImport
to false.
If useListName is true then the items will be transferred to a TaskPaper 3 project with the same name as the Reminders.app list.
If useListName
is false, and projectName
is a string, rather than undefined
, then the items will go to a project of that name (found or created if necessary)
If useListName
is false and projectName
is undefined
, then the items will simply be sent to the start of the file if atStart
is true, and to the end of the file if atStart
is false.
The TaskPaper file can be closed or open in TaskPaper 3. If it is open, then there may be a second or two of delay before the display is refreshed and you see the imported items.
It’s a rough first draft, so do experiment and test before adopting.
OPTIONS EXTRACTED FROM FOOT OF SCRIPT:
})({
RemindersListName: 'Scripting',
TaskPaper3FilePath: '~/Notes/old notes.taskpaper',
projectName: undefined, // Project to find or create (to hold imports)
useListName: true, // Use Reminders list name for above
atStart: true, // start or end of file if using neither project nor list name ?
deleteReminderAfterImport: true
});
THE FULL SCRIPT:
// DRAFT 0.03
// Import Reminders from specified list
// adding to start or end of TaskPaper 3 file,
// or to start of a named project
// See options at end of script
(function (dctOptions) {
'use strict';
// priorityName :: Int -> String
function priorityName(intLevel) {
if (intLevel > 6) return 'low';
else if (intLevel < 4) return 'hi';
else return 'med';
}
// Date -> String
function fmtTP(dte) {
var s = dte.toISOString(),
d = s.substring(0, 10);
return dte.getMinutes() ? d + ' ' + s.substring(11, 16) : d;
}
// fileExists :: String -> Bool
function fileExists(strPath) {
var fm = $.NSFileManager.defaultManager,
error = $();
fm.attributesOfItemAtPathError(
ObjC.unwrap($(strPath)
.stringByExpandingTildeInPath),
error
);
return error.code === undefined;
}
// readFile :: FilePath -> IO String
function readFile(strPath) {
return ObjC.unwrap($.NSString.stringWithContentsOfFile(strPath));
}
//writeFile :: FilePath -> String -> IO ()
function writeFile(strPath, strText) {
$.NSString.alloc.initWithUTF8String(strText)
.writeToFileAtomicallyEncodingError(
strPath, false,
$.NSUTF8StringEncoding, null
);
}
// concatMap :: (a -> [b]) -> [a] -> [b]
function concatMap(f, xs) {
return [].concat.apply([], xs.map(f));
}
var Reminders = Application('Reminders'),
lstMatch = Reminders.lists.whose({
_match: [ObjectSpecifier()
.name, dctOptions.RemindersListName]
}),
list = lstMatch.length > 0 ? lstMatch[0] : undefined;
if (list) {
var strPath = $(dctOptions.TaskPaper3FilePath)
.stringByExpandingTildeInPath.js;
if (fileExists(strPath)) {
var blnAtStart = dctOptions.atStart,
oReminders = list.reminders,
lstRem = oReminders.whose({
_match: [ObjectSpecifier()
.completed, false]
})(),
lstTodo = concatMap(function (r) {
try {
var strBody = r.body(),
dteDue = r.dueDate(),
lngHeat = r.priority();
} catch (e) {
return [];
}
return [{
id: r.id(),
lines: [[
'- ',
r.name(),
dteDue ? ' @due(' + fmtTP(dteDue) + ')' : '',
lngHeat ? ' @priority(' + priorityName(lngHeat) + ')' : ''
].join('')].concat(
strBody ? strBody.split(
/[\n\r]+/)
.map(function (para) {
return '\t' + para;
}) : []
)
}];
}, lstRem);
if (lstTodo.length > 0) {
var strProject = dctOptions.projectName,
strHeader = strProject ? strProject : (
dctOptions.useListName ? list.name() : ''
),
strLabel = strHeader + ':';
if (strHeader && strHeader.length) {
// ADD AFTER HEADER, CREATING IF NOT FOUND
var rgxProj = new RegExp(
'^(\\s*)' + strHeader + ':.*$',
'mi'
),
xs = readFile(strPath)
.split(/[\n\r]/),
i = xs.length,
dctProj,
x, m;
while (i--) {
if (xs[i].indexOf(strLabel) !== -1) {
m = xs[i].match(rgxProj);
if (m) {
dctProj = {
indent: m[1].replace(
/ /, '\t'
)
.length,
pre: xs.slice(0, i + 1),
post: xs.slice(i + 1)
}
break;
};
}
}
if (!dctProj) {
dctProj = {
indent: 0,
pre: (blnAtStart ? [] : xs)
.concat(strLabel),
post: blnAtStart ? xs : []
}
}
var strIndent = Array(dctProj.indent + 2)
.join('\t'),
strNew = dctProj.pre.join('\n') + '\n' +
lstTodo.map(function (x) {
return x.lines.map(
function (para) {
return strIndent + para;
})
.join('\n');
})
.join('\n') + '\n' +
dctProj.post.join('\n');
writeFile(
strPath,
strNew
);
// SIMPLY ADD TO START OR END OF FILE
} else {
var lstUpdate = [
lstTodo.map(function (x) {
return x.lines.join('\n');
})
.join('\n'),
'\n\n',
readFile(strPath)
];
writeFile(
strPath,
(blnAtStart ? lstUpdate :
lstUpdate
.reverse())
.join('')
)
}
// IF REQUIRED, CHECK THE IMPORT AND DELETE FROM REMINDERS.APP
if (dctOptions.deleteReminderAfterImport) {
var strUpdated = readFile(strPath);
return concatMap(function (dct) {
var strName = dct.lines[0];
if (strUpdated.indexOf(strName) !== -1) {
Reminders.delete(
oReminders.byId(dct.id)
);
return [strName];
} else {
return [];
}
}, lstTodo);
}
} // lstTodo.length > 0
} else return 'File not found: ' + dctOptions.TaskPaper3FilePath;
} else return 'No list named "' + dctOptions.RemindersListName +
'" found in Reminders';
})({
RemindersListName: 'Scripting',
TaskPaper3FilePath: '~/Notes/old notes.taskpaper',
projectName: undefined, // Project to find or create (to hold imports)
useListName: true, // Use Reminders list name for above
atStart: true, // start or end of file if using neither project nor list name ?
deleteReminderAfterImport: true
});