├── utilities
├── FT2CSV.scpt
├── CopyFTasTP.scpt
├── CopyTPasFT.scpt
├── ReadProps.scpt
├── lastLink.scpt
├── MakeTestData.scpt
├── ToggleEmpty.scpt
├── listCommands.scpt
├── Italic.kmmacros.zip
├── SafariClippings.scpt
├── MakeTestData-002.scpt
├── OpenFTDocinMarked.scpt
├── FTDueAppTimedSprint.scpt
├── GetDisplayResolution.scpt
├── SelectedMailToFTInbox.scpt
├── OpeniThoughtsMapinMarked.scpt
├── FTDueAppTimedSprint.applescript
├── GetDisplayResolution.applescript
├── CopyTPasFT.applescript
├── CopyFTasTP.applescript
├── emotime.sh
├── emomoon.sh
├── Italic.kmmacros
├── SelectedMailToFTInbox.applescript
├── OpeniThoughtsMapinMarked.applescript
├── OpenFTDocinMarked.applescript
├── FT2CSV.applescript
├── cliptextcolors.sh
├── SafariClippings.applescript
└── MakeTestData.applescript
├── copy as Markdown
├── KMAction.png
├── safariCopyAsHTML.scpt
├── safariCopyAsMDjs.scpt
├── SaveAsJavasScript-scpt.png
├── readme.md
├── safariCopyAsHTML.applescript
├── safariCopyAsMDjs.applescript
└── Copy as Markdown.kmmacros
├── structure editing
├── MoveSelnToSection.scpt
├── MoveSelnToSectionJS.scpt
├── TP3MoveSelnToSection.scpt
├── MoveSelnToSection.applescript
└── MoveSelnToSectionJS.applescript
├── ftdoc3 url scheme
├── OpenFT3DocAtLine.app.zip
├── Copy ft3doc URL for selected line in FoldingText 3.kmmacros.zip
├── Source and info.plist for OpenFT3DocAtLine
│ ├── OpenFT3DocAtLine.applescript
│ └── Info.plist
└── README.md
├── Yosemite Javascript XQuery demo
├── QueryMenu.png
├── xquery01.png
├── LinkingBackToSource.png
├── GroupedByDaysAndTimes.png
├── SampleFolder
│ ├── sortByStringLength.scpt
│ └── workProject.txt
├── readme.md
└── QueryAFolderOfOPMLFiles.applescript
├── filtering in the editor
├── ArchiveTagsMenu.scpt
├── FilterOnTagsMenu.scpt
├── FilterOnAllSelectedTags.scpt
├── tagsToggleHideFocus-js.scpt
├── tagsToggleHideFocus-minjs.scpt
├── tagsToggleHideFocus-js.applescript
├── tagsToggleHideFocus-minjs.applescript
├── FilterOnTagsMenu.applescript
├── ArchiveTagsMenu.applescript
└── FilterOnAllSelectedTags.applescript
├── import and export formats
├── FT2ImportOPML.scpt
├── FTSaveAsOPML-js.scpt
├── FT2ImportOPML.applescript
└── FTSaveAsOPML-js.applescript
├── toggle hide done items.ftplugin
├── unfocus.scpt
├── package.json
├── HideDone-002.applescript
├── spec.js
└── main.js
├── ftdoc url scheme and FTCopyAsURL
├── FTCopyAsURL.scpt
├── Source and info.plist for OpenFTDocAtLine
│ ├── Info.plist
│ └── OpenFTDocAtLine.applescript
├── FTCopyAsURL.applescript
└── README.md
├── perspectives.ftplugin
├── SingleFilePerspectives.scpt
├── package.json
├── Example TXTQUERY.sh from KM.kmmacros
├── README.md
└── ViewMenu.json
├── tp3doc url scheme and TP3CopyAsURL
├── TP3CopyAsURL.scpt
├── Source and info.plist for OpenTP3DocAtLine
│ ├── Info.plist
│ └── OpenTP3DocAtLine.applescript
├── TP3CopyAsURL.applescript
└── README.md
├── relative dates and date adjustments.ftplugin
├── E Adjust.png
├── C AfterEntry.png
├── F AfterAdjust.png
├── D AutoSelectDateTime.png
├── A PlaceCursorInOrNextToTag.png
├── B InformalPhraseTranslatedLive.png
├── package.json
├── style.less
├── README.md
├── TaskPaper.textexpander
├── FoldingTextOLD.textexpander
└── main.js
├── links between plain text and Reminders
├── CopyReminderAsMD.png
├── ReminderUpdated.png
├── x-apple-reminder.png
├── CopyReminderAsLink.png
├── CopyReminderAsLink.scpt
├── SelectLineWithAlert.png
├── FTMakeOrUpdateReminder.png
├── LinkBackFromReminder.png
├── PlainTextToReminders.png
├── FTMakeOrUpdateReminder.scpt
├── Icon and time normalized.png
├── CopyReminderAsLink.applescript
├── CopyReminderAsTaskPaperorFT.png
├── Edits to date and priority.png
├── CopyReminderAsTaskPaperOrFT.scpt
├── FTToggleDoneUpdateReminders.scpt
├── FTMakeOrUpdateReminder.applescript
├── FTPullDetailsFROMLinkedReminder.scpt
├── CopyReminderAsTaskPaperOrFT.applescript
├── FTToggleDoneUpdateReminders.applescript
├── FTPullDetailsFROMLinkedReminder.applescript
├── FTMakeOrUpdateReminder.workflow
│ └── Contents
│ │ ├── QuickLook
│ │ └── Thumbnail.png
│ │ └── Info.plist
└── README.md
├── Copy paste and Open Save As between FT MD and FTML
├── FTML2MD.scpt
├── FTML2MD-006.scpt
├── FTML2MD-007.scpt
├── storeQuery.scpt
├── FTSaveAsFTML.scpt
├── FTTextPasteAsFTML.scpt
├── archived BML versions
│ ├── BML2MD.scpt
│ └── FTSaveAsBML.scpt
└── readme.md
├── smalltime.ftplugin
└── package.json
├── reminder tools.ftplugin
├── package.json
├── updatelink.js
└── main.js
└── README.md
/utilities/FT2CSV.scpt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RobTrew/txtquery-tools/HEAD/utilities/FT2CSV.scpt
--------------------------------------------------------------------------------
/utilities/CopyFTasTP.scpt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RobTrew/txtquery-tools/HEAD/utilities/CopyFTasTP.scpt
--------------------------------------------------------------------------------
/utilities/CopyTPasFT.scpt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RobTrew/txtquery-tools/HEAD/utilities/CopyTPasFT.scpt
--------------------------------------------------------------------------------
/utilities/ReadProps.scpt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RobTrew/txtquery-tools/HEAD/utilities/ReadProps.scpt
--------------------------------------------------------------------------------
/utilities/lastLink.scpt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RobTrew/txtquery-tools/HEAD/utilities/lastLink.scpt
--------------------------------------------------------------------------------
/utilities/MakeTestData.scpt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RobTrew/txtquery-tools/HEAD/utilities/MakeTestData.scpt
--------------------------------------------------------------------------------
/utilities/ToggleEmpty.scpt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RobTrew/txtquery-tools/HEAD/utilities/ToggleEmpty.scpt
--------------------------------------------------------------------------------
/utilities/listCommands.scpt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RobTrew/txtquery-tools/HEAD/utilities/listCommands.scpt
--------------------------------------------------------------------------------
/copy as Markdown/KMAction.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RobTrew/txtquery-tools/HEAD/copy as Markdown/KMAction.png
--------------------------------------------------------------------------------
/utilities/Italic.kmmacros.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RobTrew/txtquery-tools/HEAD/utilities/Italic.kmmacros.zip
--------------------------------------------------------------------------------
/utilities/SafariClippings.scpt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RobTrew/txtquery-tools/HEAD/utilities/SafariClippings.scpt
--------------------------------------------------------------------------------
/utilities/MakeTestData-002.scpt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RobTrew/txtquery-tools/HEAD/utilities/MakeTestData-002.scpt
--------------------------------------------------------------------------------
/utilities/OpenFTDocinMarked.scpt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RobTrew/txtquery-tools/HEAD/utilities/OpenFTDocinMarked.scpt
--------------------------------------------------------------------------------
/utilities/FTDueAppTimedSprint.scpt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RobTrew/txtquery-tools/HEAD/utilities/FTDueAppTimedSprint.scpt
--------------------------------------------------------------------------------
/utilities/GetDisplayResolution.scpt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RobTrew/txtquery-tools/HEAD/utilities/GetDisplayResolution.scpt
--------------------------------------------------------------------------------
/utilities/SelectedMailToFTInbox.scpt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RobTrew/txtquery-tools/HEAD/utilities/SelectedMailToFTInbox.scpt
--------------------------------------------------------------------------------
/copy as Markdown/safariCopyAsHTML.scpt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RobTrew/txtquery-tools/HEAD/copy as Markdown/safariCopyAsHTML.scpt
--------------------------------------------------------------------------------
/copy as Markdown/safariCopyAsMDjs.scpt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RobTrew/txtquery-tools/HEAD/copy as Markdown/safariCopyAsMDjs.scpt
--------------------------------------------------------------------------------
/structure editing/MoveSelnToSection.scpt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RobTrew/txtquery-tools/HEAD/structure editing/MoveSelnToSection.scpt
--------------------------------------------------------------------------------
/utilities/OpeniThoughtsMapinMarked.scpt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RobTrew/txtquery-tools/HEAD/utilities/OpeniThoughtsMapinMarked.scpt
--------------------------------------------------------------------------------
/ftdoc3 url scheme/OpenFT3DocAtLine.app.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RobTrew/txtquery-tools/HEAD/ftdoc3 url scheme/OpenFT3DocAtLine.app.zip
--------------------------------------------------------------------------------
/structure editing/MoveSelnToSectionJS.scpt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RobTrew/txtquery-tools/HEAD/structure editing/MoveSelnToSectionJS.scpt
--------------------------------------------------------------------------------
/utilities/FTDueAppTimedSprint.applescript:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RobTrew/txtquery-tools/HEAD/utilities/FTDueAppTimedSprint.applescript
--------------------------------------------------------------------------------
/Yosemite Javascript XQuery demo/QueryMenu.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RobTrew/txtquery-tools/HEAD/Yosemite Javascript XQuery demo/QueryMenu.png
--------------------------------------------------------------------------------
/Yosemite Javascript XQuery demo/xquery01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RobTrew/txtquery-tools/HEAD/Yosemite Javascript XQuery demo/xquery01.png
--------------------------------------------------------------------------------
/copy as Markdown/SaveAsJavasScript-scpt.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RobTrew/txtquery-tools/HEAD/copy as Markdown/SaveAsJavasScript-scpt.png
--------------------------------------------------------------------------------
/filtering in the editor/ArchiveTagsMenu.scpt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RobTrew/txtquery-tools/HEAD/filtering in the editor/ArchiveTagsMenu.scpt
--------------------------------------------------------------------------------
/filtering in the editor/FilterOnTagsMenu.scpt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RobTrew/txtquery-tools/HEAD/filtering in the editor/FilterOnTagsMenu.scpt
--------------------------------------------------------------------------------
/import and export formats/FT2ImportOPML.scpt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RobTrew/txtquery-tools/HEAD/import and export formats/FT2ImportOPML.scpt
--------------------------------------------------------------------------------
/structure editing/TP3MoveSelnToSection.scpt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RobTrew/txtquery-tools/HEAD/structure editing/TP3MoveSelnToSection.scpt
--------------------------------------------------------------------------------
/toggle hide done items.ftplugin/unfocus.scpt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RobTrew/txtquery-tools/HEAD/toggle hide done items.ftplugin/unfocus.scpt
--------------------------------------------------------------------------------
/import and export formats/FTSaveAsOPML-js.scpt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RobTrew/txtquery-tools/HEAD/import and export formats/FTSaveAsOPML-js.scpt
--------------------------------------------------------------------------------
/structure editing/MoveSelnToSection.applescript:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RobTrew/txtquery-tools/HEAD/structure editing/MoveSelnToSection.applescript
--------------------------------------------------------------------------------
/ftdoc url scheme and FTCopyAsURL/FTCopyAsURL.scpt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RobTrew/txtquery-tools/HEAD/ftdoc url scheme and FTCopyAsURL/FTCopyAsURL.scpt
--------------------------------------------------------------------------------
/perspectives.ftplugin/SingleFilePerspectives.scpt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RobTrew/txtquery-tools/HEAD/perspectives.ftplugin/SingleFilePerspectives.scpt
--------------------------------------------------------------------------------
/filtering in the editor/FilterOnAllSelectedTags.scpt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RobTrew/txtquery-tools/HEAD/filtering in the editor/FilterOnAllSelectedTags.scpt
--------------------------------------------------------------------------------
/filtering in the editor/tagsToggleHideFocus-js.scpt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RobTrew/txtquery-tools/HEAD/filtering in the editor/tagsToggleHideFocus-js.scpt
--------------------------------------------------------------------------------
/import and export formats/FT2ImportOPML.applescript:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RobTrew/txtquery-tools/HEAD/import and export formats/FT2ImportOPML.applescript
--------------------------------------------------------------------------------
/tp3doc url scheme and TP3CopyAsURL/TP3CopyAsURL.scpt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RobTrew/txtquery-tools/HEAD/tp3doc url scheme and TP3CopyAsURL/TP3CopyAsURL.scpt
--------------------------------------------------------------------------------
/Yosemite Javascript XQuery demo/LinkingBackToSource.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RobTrew/txtquery-tools/HEAD/Yosemite Javascript XQuery demo/LinkingBackToSource.png
--------------------------------------------------------------------------------
/filtering in the editor/tagsToggleHideFocus-minjs.scpt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RobTrew/txtquery-tools/HEAD/filtering in the editor/tagsToggleHideFocus-minjs.scpt
--------------------------------------------------------------------------------
/import and export formats/FTSaveAsOPML-js.applescript:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RobTrew/txtquery-tools/HEAD/import and export formats/FTSaveAsOPML-js.applescript
--------------------------------------------------------------------------------
/Yosemite Javascript XQuery demo/GroupedByDaysAndTimes.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RobTrew/txtquery-tools/HEAD/Yosemite Javascript XQuery demo/GroupedByDaysAndTimes.png
--------------------------------------------------------------------------------
/relative dates and date adjustments.ftplugin/E Adjust.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RobTrew/txtquery-tools/HEAD/relative dates and date adjustments.ftplugin/E Adjust.png
--------------------------------------------------------------------------------
/filtering in the editor/tagsToggleHideFocus-js.applescript:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RobTrew/txtquery-tools/HEAD/filtering in the editor/tagsToggleHideFocus-js.applescript
--------------------------------------------------------------------------------
/links between plain text and Reminders/CopyReminderAsMD.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RobTrew/txtquery-tools/HEAD/links between plain text and Reminders/CopyReminderAsMD.png
--------------------------------------------------------------------------------
/links between plain text and Reminders/ReminderUpdated.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RobTrew/txtquery-tools/HEAD/links between plain text and Reminders/ReminderUpdated.png
--------------------------------------------------------------------------------
/links between plain text and Reminders/x-apple-reminder.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RobTrew/txtquery-tools/HEAD/links between plain text and Reminders/x-apple-reminder.png
--------------------------------------------------------------------------------
/links between plain text and Reminders/CopyReminderAsLink.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RobTrew/txtquery-tools/HEAD/links between plain text and Reminders/CopyReminderAsLink.png
--------------------------------------------------------------------------------
/links between plain text and Reminders/CopyReminderAsLink.scpt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RobTrew/txtquery-tools/HEAD/links between plain text and Reminders/CopyReminderAsLink.scpt
--------------------------------------------------------------------------------
/links between plain text and Reminders/SelectLineWithAlert.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RobTrew/txtquery-tools/HEAD/links between plain text and Reminders/SelectLineWithAlert.png
--------------------------------------------------------------------------------
/relative dates and date adjustments.ftplugin/C AfterEntry.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RobTrew/txtquery-tools/HEAD/relative dates and date adjustments.ftplugin/C AfterEntry.png
--------------------------------------------------------------------------------
/relative dates and date adjustments.ftplugin/F AfterAdjust.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RobTrew/txtquery-tools/HEAD/relative dates and date adjustments.ftplugin/F AfterAdjust.png
--------------------------------------------------------------------------------
/Copy paste and Open Save As between FT MD and FTML/FTML2MD.scpt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RobTrew/txtquery-tools/HEAD/Copy paste and Open Save As between FT MD and FTML/FTML2MD.scpt
--------------------------------------------------------------------------------
/links between plain text and Reminders/FTMakeOrUpdateReminder.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RobTrew/txtquery-tools/HEAD/links between plain text and Reminders/FTMakeOrUpdateReminder.png
--------------------------------------------------------------------------------
/links between plain text and Reminders/LinkBackFromReminder.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RobTrew/txtquery-tools/HEAD/links between plain text and Reminders/LinkBackFromReminder.png
--------------------------------------------------------------------------------
/links between plain text and Reminders/PlainTextToReminders.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RobTrew/txtquery-tools/HEAD/links between plain text and Reminders/PlainTextToReminders.png
--------------------------------------------------------------------------------
/Copy paste and Open Save As between FT MD and FTML/FTML2MD-006.scpt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RobTrew/txtquery-tools/HEAD/Copy paste and Open Save As between FT MD and FTML/FTML2MD-006.scpt
--------------------------------------------------------------------------------
/Copy paste and Open Save As between FT MD and FTML/FTML2MD-007.scpt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RobTrew/txtquery-tools/HEAD/Copy paste and Open Save As between FT MD and FTML/FTML2MD-007.scpt
--------------------------------------------------------------------------------
/Copy paste and Open Save As between FT MD and FTML/storeQuery.scpt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RobTrew/txtquery-tools/HEAD/Copy paste and Open Save As between FT MD and FTML/storeQuery.scpt
--------------------------------------------------------------------------------
/links between plain text and Reminders/FTMakeOrUpdateReminder.scpt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RobTrew/txtquery-tools/HEAD/links between plain text and Reminders/FTMakeOrUpdateReminder.scpt
--------------------------------------------------------------------------------
/links between plain text and Reminders/Icon and time normalized.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RobTrew/txtquery-tools/HEAD/links between plain text and Reminders/Icon and time normalized.png
--------------------------------------------------------------------------------
/Copy paste and Open Save As between FT MD and FTML/FTSaveAsFTML.scpt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RobTrew/txtquery-tools/HEAD/Copy paste and Open Save As between FT MD and FTML/FTSaveAsFTML.scpt
--------------------------------------------------------------------------------
/Yosemite Javascript XQuery demo/SampleFolder/sortByStringLength.scpt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RobTrew/txtquery-tools/HEAD/Yosemite Javascript XQuery demo/SampleFolder/sortByStringLength.scpt
--------------------------------------------------------------------------------
/links between plain text and Reminders/CopyReminderAsLink.applescript:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RobTrew/txtquery-tools/HEAD/links between plain text and Reminders/CopyReminderAsLink.applescript
--------------------------------------------------------------------------------
/links between plain text and Reminders/CopyReminderAsTaskPaperorFT.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RobTrew/txtquery-tools/HEAD/links between plain text and Reminders/CopyReminderAsTaskPaperorFT.png
--------------------------------------------------------------------------------
/links between plain text and Reminders/Edits to date and priority.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RobTrew/txtquery-tools/HEAD/links between plain text and Reminders/Edits to date and priority.png
--------------------------------------------------------------------------------
/relative dates and date adjustments.ftplugin/D AutoSelectDateTime.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RobTrew/txtquery-tools/HEAD/relative dates and date adjustments.ftplugin/D AutoSelectDateTime.png
--------------------------------------------------------------------------------
/links between plain text and Reminders/CopyReminderAsTaskPaperOrFT.scpt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RobTrew/txtquery-tools/HEAD/links between plain text and Reminders/CopyReminderAsTaskPaperOrFT.scpt
--------------------------------------------------------------------------------
/links between plain text and Reminders/FTToggleDoneUpdateReminders.scpt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RobTrew/txtquery-tools/HEAD/links between plain text and Reminders/FTToggleDoneUpdateReminders.scpt
--------------------------------------------------------------------------------
/Copy paste and Open Save As between FT MD and FTML/FTTextPasteAsFTML.scpt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RobTrew/txtquery-tools/HEAD/Copy paste and Open Save As between FT MD and FTML/FTTextPasteAsFTML.scpt
--------------------------------------------------------------------------------
/links between plain text and Reminders/FTMakeOrUpdateReminder.applescript:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RobTrew/txtquery-tools/HEAD/links between plain text and Reminders/FTMakeOrUpdateReminder.applescript
--------------------------------------------------------------------------------
/links between plain text and Reminders/FTPullDetailsFROMLinkedReminder.scpt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RobTrew/txtquery-tools/HEAD/links between plain text and Reminders/FTPullDetailsFROMLinkedReminder.scpt
--------------------------------------------------------------------------------
/relative dates and date adjustments.ftplugin/A PlaceCursorInOrNextToTag.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RobTrew/txtquery-tools/HEAD/relative dates and date adjustments.ftplugin/A PlaceCursorInOrNextToTag.png
--------------------------------------------------------------------------------
/links between plain text and Reminders/CopyReminderAsTaskPaperOrFT.applescript:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RobTrew/txtquery-tools/HEAD/links between plain text and Reminders/CopyReminderAsTaskPaperOrFT.applescript
--------------------------------------------------------------------------------
/links between plain text and Reminders/FTToggleDoneUpdateReminders.applescript:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RobTrew/txtquery-tools/HEAD/links between plain text and Reminders/FTToggleDoneUpdateReminders.applescript
--------------------------------------------------------------------------------
/relative dates and date adjustments.ftplugin/B InformalPhraseTranslatedLive.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RobTrew/txtquery-tools/HEAD/relative dates and date adjustments.ftplugin/B InformalPhraseTranslatedLive.png
--------------------------------------------------------------------------------
/ftdoc3 url scheme/Copy ft3doc URL for selected line in FoldingText 3.kmmacros.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RobTrew/txtquery-tools/HEAD/ftdoc3 url scheme/Copy ft3doc URL for selected line in FoldingText 3.kmmacros.zip
--------------------------------------------------------------------------------
/links between plain text and Reminders/FTPullDetailsFROMLinkedReminder.applescript:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RobTrew/txtquery-tools/HEAD/links between plain text and Reminders/FTPullDetailsFROMLinkedReminder.applescript
--------------------------------------------------------------------------------
/Copy paste and Open Save As between FT MD and FTML/archived BML versions/BML2MD.scpt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RobTrew/txtquery-tools/HEAD/Copy paste and Open Save As between FT MD and FTML/archived BML versions/BML2MD.scpt
--------------------------------------------------------------------------------
/Copy paste and Open Save As between FT MD and FTML/archived BML versions/FTSaveAsBML.scpt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RobTrew/txtquery-tools/HEAD/Copy paste and Open Save As between FT MD and FTML/archived BML versions/FTSaveAsBML.scpt
--------------------------------------------------------------------------------
/links between plain text and Reminders/FTMakeOrUpdateReminder.workflow/Contents/QuickLook/Thumbnail.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RobTrew/txtquery-tools/HEAD/links between plain text and Reminders/FTMakeOrUpdateReminder.workflow/Contents/QuickLook/Thumbnail.png
--------------------------------------------------------------------------------
/links between plain text and Reminders/FTMakeOrUpdateReminder.workflow/Contents/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleName
6 | FTMakeOrUpdateReminder
7 |
8 |
9 |
--------------------------------------------------------------------------------
/perspectives.ftplugin/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "Custom perspectives",
3 | "version": "1.2.0",
4 | "description": "Plain text reports grouped and sorted by @tag(values)",
5 | "engines": {
6 | "foldingtext": ">=2.0.0",
7 | "taskpaper": ">=3.0.0"
8 | },
9 | "homepage": "https://github.com/RobTrew/tree-tools"
10 | }
11 |
12 |
--------------------------------------------------------------------------------
/toggle hide done items.ftplugin/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "Toggle Hide Done Items",
3 | "version": "1.0.2",
4 | "description": "Toggles visibility of @done items on and off. See Edit > Run Command",
5 | "homepage": "https://github.com/RobTrew/txtquery-tools",
6 | "engines": {
7 | "foldingtext": ">2.0.0",
8 | "taskpaper": ">3.0.0"
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/relative dates and date adjustments.ftplugin/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "Live translation of relative and informal dates to ISO",
3 | "version": "1.3.1",
4 | "description": "Uses JK Panel",
5 | "engines": {
6 | "foldingtext": ">=2.0.0",
7 | "taskpaper": ">=3.0.0"
8 | },
9 | "homepage": "https://github.com/RobTrew/tree-tools"
10 | }
11 |
12 |
--------------------------------------------------------------------------------
/smalltime.ftplugin/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "Exports informal/relative date phrase translation functions",
3 | "version": "1.3.1",
4 | "description": "Library functions used by other plugins",
5 | "engines": {
6 | "foldingtext": ">=2.0.0",
7 | "taskpaper": ">=3.0.0"
8 | },
9 | "homepage": "https://github.com/RobTrew/tree-tools"
10 | }
11 |
12 |
--------------------------------------------------------------------------------
/reminder tools.ftplugin/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "Functions for sharing data with Reminders.app entries",
3 | "version": "1.3.1",
4 | "description": "Manages links and date tag reading and writing",
5 | "engines": {
6 | "foldingtext": ">=2.0.0",
7 | "taskpaper": ">=3.0.0"
8 | },
9 | "homepage": "https://github.com/RobTrew/tree-tools"
10 | }
11 |
12 |
--------------------------------------------------------------------------------
/reminder tools.ftplugin/updatelink.js:
--------------------------------------------------------------------------------
1 | function(editor, options) {
2 | 'use strict';
3 | var tree = editor.tree(),
4 | node = editor.selectedRange().startNode, strText=node.text(), strUUID=options.uuid, rgxLink, strUpdated;
5 | rgxLink= new RegExp('\\[.*\\](' + strUUID + ')');
6 | debugger;
7 | strUpdated = strText.replace(rgxLink, '[' + options.linkname + '](' +strUUID + ')');
8 | tree.beginUpdates();
9 | node.setText(strUpdated);
10 | tree.endUpdates();
11 | tree.ensureClassified();
12 | }
13 |
--------------------------------------------------------------------------------
/ftdoc3 url scheme/Source and info.plist for OpenFT3DocAtLine/OpenFT3DocAtLine.applescript:
--------------------------------------------------------------------------------
1 | property pTitle : "Register and handle ft3doc:// url scheme"
2 | property pVer : "0.01"
3 | property pAuthor : "Rob Trew @complexpoint"
4 | property pDescription : "
5 |
6 | Use in conjunction with Atom > Edit > Copy Path (Ctrl Shift C) to copy
7 | a URL which opens the specified FoldingText 3 document, selecting the line at which the path was copied.
8 | https://github.com/FoldingText/foldingtext-for-atom
9 |
10 | "
11 | on open location strFT3URL
12 | do shell script "/usr/local/bin/atom file" & (text 7 thru -1 of strFT3URL)
13 | end open location
14 |
--------------------------------------------------------------------------------
/relative dates and date adjustments.ftplugin/style.less:
--------------------------------------------------------------------------------
1 | // Jamie Kowalki's LESS code adapted for a date panel
2 |
3 | @panel-width: 800px;
4 | @panel-height: 1.9rem;
5 |
6 | .RTDatePanel {
7 | position: fixed;
8 | z-index: 10;
9 | left: 25px;
10 | top: 8px;
11 | width: @panel-width;
12 | height: @panel-height;
13 | background-color: white;
14 | border-radius: 6px;
15 | box-shadow: 1px 3px 10px #999;
16 | }
17 | .RTDatePanel input {
18 | margin: 5px 10px;
19 | width: @panel-width - 20px;
20 | height: @panel-height - 10px;
21 | background: inherit;
22 | border: none;
23 | font-size: 1em;
24 | font-family: inherit;
25 | }
26 | .RTDatePanel input:focus {
27 | outline-width: 0;
28 | }
29 |
--------------------------------------------------------------------------------
/utilities/GetDisplayResolution.applescript:
--------------------------------------------------------------------------------
1 | -- properties persist across sessions in compiled .scpt files
2 | -- so subsequent runs will be faster
3 | property pX : missing value
4 | property pY : missing value
5 |
6 |
7 | on run {}
8 | displayResoln()
9 | end run
10 |
11 | on displayResoln()
12 | if (pX is missing value) or (pY is missing value) then
13 | set {dlm, my text item delimiters} to {my text item delimiters, "Resolution"}
14 | set lstDisplays to text items of (do shell script "system_profiler SPDisplaysDataType")
15 |
16 | repeat with i from 2 to length of lstDisplays
17 | set strLine to item i of lstDisplays
18 | if strLine contains "Main Display: Yes" then exit repeat
19 | end repeat
20 | set my text item delimiters to space
21 | set lstParts to text items of strLine
22 | set my text item delimiters to dlm
23 | set {strX, strY} to {item 2, item 4} of lstParts
24 | set {pX, pY} to {strX as integer, strY as integer}
25 | end if
26 | return {pX , pY}
27 | end displayResoln
--------------------------------------------------------------------------------
/Copy paste and Open Save As between FT MD and FTML/readme.md:
--------------------------------------------------------------------------------
1 | #### FoldingText MD ⇄ FoldingText for Atom HTML (.ftml) outlines
2 |
3 | A couple of **Yosemite Javascript for Applications** Scripts which can be run from Script Editor or assigned to keystrokes with something like Keyboard Maestro.
4 |
5 | 1. [FoldingText / MD --> FTML outline](./FTSaveAsFTML.applescript)
6 | 3. [FTML outline --> FoldingText MD format](./FTML2MD.applescript)
7 |
8 | Both can be used either for clipboard copy paste or for file system Open and Save As
9 |
10 | (Probably makes sense to save two versions of each, adjusting the options switches at the top of each script to 0 or 1 values to select between clipboard and file operations)
11 |
12 | Note: Ver 12 and above of the FoldingText Save As FTML script use CommonMark (rather than FoldingText) line type names.
13 |
14 | **Installation** - paste the code into Yosemite Script Editor, setting the editor language option to **Javascript** (pull-down option at top left), and save as a compiled .scpt file
15 |
--------------------------------------------------------------------------------
/toggle hide done items.ftplugin/HideDone-002.applescript:
--------------------------------------------------------------------------------
1 | -- ver 1.0.2 toggles visibility of @done without losing any existing focus
property pstrJS : "
2 |
3 | function(editor) {
4 | var strActivePath = editor.nodePath().nodePathString,
5 | lstNodes,
6 | strExceptDone = ' except //@done', lngChars=strExceptDone.length,
7 | strToggledPath, lngStart;
8 |
9 | switch (strActivePath) {
10 | case '///*':
11 | strToggledPath = '//not @done';
12 | break;
13 | case '//not @done':
14 | strToggledPath = '///*';
15 | break;
16 | default :
17 | lngStart = strActivePath.length-lngChars;
18 | if (strActivePath.indexOf(' except //@done', lngStart) == -1)
19 | strToggledPath = strActivePath + strExceptDone;
20 | else
21 | strToggledPath = strActivePath.substring(0, lngStart);
22 | break;
23 | }
24 | editor.setNodePath(strToggledPath);
25 | }
26 |
27 | "
tell application "FoldingText"
set lstDocs to documents
if lstDocs ≠ {} then
tell item 1 of lstDocs to (evaluate script pstrJS)
end if
end tell
--------------------------------------------------------------------------------
/toggle hide done items.ftplugin/spec.js:
--------------------------------------------------------------------------------
1 | define(function (require) {
2 | 'use strict';
3 |
4 | describe('toggle hide done items', function () {
5 | var MarkdownTaxonomy = require('ft/taxonomy/markdowntaxonomy').MarkdownTaxonomy,
6 | Taxonomies = require('ft/core/taxonomies'),
7 | Editor = require('ft/editor/editor').Editor,
8 | taxonomy = Taxonomies.taxonomy({
9 | foldingtext: true,
10 | multimarkdown: true,
11 | gitmarkdown: true,
12 | criticMarkup: true
13 | }, 'markdown'),
14 | editor;
15 |
16 | beforeEach(function () {
17 | editor = new Editor('', taxonomy);
18 | });
19 |
20 | afterEach(function () {
21 | editor.removeAndCleanupForCollection();
22 | });
23 |
24 | it('should toggle path between //not @done and ///*', function () {
25 | editor.setNodePath('///*');
26 | editor.performCommand('toggle hide done items');
27 | expect(editor.nodePath().nodePathString).toEqual('//not @done');
28 | editor.performCommand('toggle hide done items');
29 | expect(editor.nodePath().nodePathString).toEqual('///*');
30 | });
31 | });
32 | });
33 |
--------------------------------------------------------------------------------
/toggle hide done items.ftplugin/main.js:
--------------------------------------------------------------------------------
1 | define(function(require, exports, module) {
2 | var Extensions = require('ft/core/extensions').Extensions;
3 |
4 | Extensions.addCommand({
5 | name: 'toggle hide done items',
6 | description: 'Toggles between hiding @done items and showing all lines',
7 | performCommand: function(editor) {
8 | var strActivePath = editor.nodePath().nodePathString,
9 | lstNodes,
10 | strExceptDone = ' except //@done',
11 | lngChars=strExceptDone.length,
12 | strToggledPath, lngStart;
13 |
14 | switch (strActivePath) {
15 | case '///*':
16 | strToggledPath = '//not @done';
17 | break;
18 | case '//not @done':
19 | strToggledPath = '///*';
20 | break;
21 | default :
22 | lngStart = strActivePath.length-lngChars;
23 | if (strActivePath.indexOf(
24 | ' except //@done', lngStart) == -1)
25 | strToggledPath = strActivePath + strExceptDone;
26 | else
27 | strToggledPath = strActivePath.substring(0, lngStart);
28 | break;
29 | }
30 | editor.setNodePath(strToggledPath);
31 | }
32 | });
33 |
34 | Extensions.addInit(function (editor) {
35 | editor.addKeyMap({
36 | 'Cmd-Ctrl-Alt-H':'toggle hide done items'
37 | });
38 | });
39 | });
40 |
--------------------------------------------------------------------------------
/copy as Markdown/readme.md:
--------------------------------------------------------------------------------
1 | ## Copy as MD for Safari (Yosemite)
2 |
3 | ### Use
4 | - Select some paragraphs in Safari,
5 | - run the script from a keyboard assignment,
6 | - and paste the paragraphs somewhere as [Markdown-formatted](http://daringfireball.net/projects/markdown/syntax) text.
7 |
8 | ### Requirements
9 | 1. OS X 10.10 (Yosemite)
10 | 2. [safariCopyAsMDjs.applescript](./safariCopyAsMDjs.applescript)
11 | (Written in Yosemite JXA - Javascript for Automation)
12 | 3. A copy of the [html2text.py](https://github.com/aaronsw/html2text) Python text file
13 | (place it in the same folder as [safariCopyAsMDjs.applescript](./safariCopyAsMDjs.applescript))
14 |
15 | ### Installation
16 | - Use OS X Yosemite Script Editor to save a copy of [safariCopyAsMDjs.applescript](./safariCopyAsMDjs.applescript) as a compiled Javascript .scpt file
17 |
18 | 
19 |
20 | - Place a copy of the [html2text.py](https://github.com/aaronsw/html2text) text file in the same folder as this script.
21 |
22 | - Assign a keyboard shortcut to safariCopyAsMDjs.scpt
23 | - with something like [Keyboard Maestro](http://www.keyboardmaestro.com)
24 |
25 | 
26 |
27 | - or [Fastscripts](http://www.red-sweater.com/fastscripts/)
28 |
--------------------------------------------------------------------------------
/ftdoc url scheme and FTCopyAsURL/Source and info.plist for OpenFTDocAtLine/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleAllowMixedLocalizations
6 |
7 | CFBundleDevelopmentRegion
8 | English
9 | CFBundleExecutable
10 | applet
11 | CFBundleIconFile
12 | applet
13 | CFBundleIdentifier
14 | com.complexpoint.OpenFTDocAtLine
15 | CFBundleInfoDictionaryVersion
16 | 6.0
17 | CFBundleName
18 | OpenFTDocAtLine
19 | CFBundlePackageType
20 | APPL
21 | CFBundleSignature
22 | aplt
23 | CFBundleURLTypes
24 |
25 |
26 | CFBundleURLName
27 | Links to FoldingText docs
28 | CFBundleURLSchemes
29 |
30 | ftdoc
31 |
32 |
33 |
34 | LSMinimumSystemVersionByArchitecture
35 |
36 | x86_64
37 | 10.6
38 |
39 | LSRequiresCarbon
40 |
41 |
42 |
43 |
--------------------------------------------------------------------------------
/tp3doc url scheme and TP3CopyAsURL/Source and info.plist for OpenTP3DocAtLine/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleAllowMixedLocalizations
6 |
7 | CFBundleDevelopmentRegion
8 | English
9 | CFBundleExecutable
10 | applet
11 | CFBundleIconFile
12 | applet
13 | CFBundleIdentifier
14 | com.complexpoint.OpenTP3DocAtLine
15 | CFBundleInfoDictionaryVersion
16 | 6.0
17 | CFBundleName
18 | OpenTP3DocAtLine
19 | CFBundlePackageType
20 | APPL
21 | CFBundleSignature
22 | aplt
23 | CFBundleURLTypes
24 |
25 |
26 | CFBundleURLName
27 | Links to TaskPaper3 docs
28 | CFBundleURLSchemes
29 |
30 | tp3doc
31 |
32 |
33 |
34 | LSMinimumSystemVersionByArchitecture
35 |
36 | x86_64
37 | 10.6
38 |
39 | LSRequiresCarbon
40 |
41 |
42 |
43 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | txtquery-tools
2 | ==========
3 |
4 | Various scripts for generating grouped, sorted and hyperlinked custom reports and perspectives from _key@value_ tagged text files in the [FoldingText](http://www.foldingtext.com) and [TaskPaper](http://www.hogbaysoftware.com) formats.
5 |
6 | License for the code in this repository:
7 |
8 | Copyright © 2014 Robin Trew
9 | --
10 |
11 | Permission is hereby granted, free of charge,
12 | to any person obtaining a copy of this software
13 | and associated documentation files (the "Software"),
14 | to deal in the Software without restriction,
15 | including without limitation the rights to use, copy,
16 | modify, merge, publish, distribute, sublicense,
17 | and/or sell copies of the Software, and to permit persons
18 | to whom the Software is furnished to do so,
19 | subject to the following conditions:
20 |
21 | *******
22 | The above copyright notice and this permission notice
23 | shall be included in ALL copies
24 | or substantial portions of the Software.
25 | *******
26 |
27 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
28 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
29 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
30 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
31 | DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
32 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
33 | OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
34 |
--------------------------------------------------------------------------------
/utilities/CopyTPasFT.applescript:
--------------------------------------------------------------------------------
1 | property pTitle : "Copy from TaskPaper in FOLDINGTEXT format"
property pVer : "0.1"
property pAuthor : "Rob Trew @complexpoint on Twitter"
property pRepo : "https://github.com/RobTrew/txtquery-tools"
property pLicense : "MIT"
property pstrJS : "
2 |
3 |
4 | function(editor, options) {
5 |
6 | // HOW MANY PRECEDING TABS OR HASHES FOR THIS LINE IN FT ?
7 | function FTPrefix(oNode) {
8 | var oParent=oNode.parent, lngLevel=1, lngProjLevel=1, blnFound=false,
9 | strType=oNode.type(), blnProj = (strType == 'project'), strPrefix;
10 |
11 | blnFound = blnProj;
12 | while (oParent) {
13 | lngLevel++;
14 | if (blnFound) lngProjLevel ++;
15 | else blnFound = (oParent.type() == 'project');
16 | oParent = oParent.parent;
17 | }
18 | if (blnProj) strPrefix = '\\n' + Array(lngLevel).join('#') + ' ';
19 | else strPrefix = Array(lngLevel-lngProjLevel).join('\\t');
20 |
21 | return strPrefix;
22 | }
23 |
24 | // GET THE SELECTED LINES
25 | var lstNodes = editor.selectedRange().nodesInRange(),
26 | lstLines=[], varNode, strLine, rgxEndColon = /^(.*):(.*?)$/;
27 |
28 | // AND GIVE AN FT PREFIX (HASHES OR TABS) TO EACH ONE
29 | lstNodes.forEach(function (oNode) {
30 | strLine = oNode.line().trim();
31 |
32 | // REMOVING THE COLON FROM PROJECTS (BUT LEAVING TRAILLING TAGS)
33 | if (oNode.type() == 'project')
34 | strLine=strLine.replace(rgxEndColon, '$1$2');
35 | lstLines.push([FTPrefix(oNode),strLine].join(''));
36 | });
37 |
38 | return lstLines.join('\\n');
39 | }
40 |
41 | "
on run
set varResult to missing value
tell application "TaskPaper"
set lstDocs to documents
if lstDocs ≠ {} then
tell item 1 of lstDocs to set varResult to (evaluate script pstrJS)
set the clipboard to varResult
end if
end tell
return varResult
end run
--------------------------------------------------------------------------------
/ftdoc3 url scheme/Source and info.plist for OpenFT3DocAtLine/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleAllowMixedLocalizations
6 |
7 | CFBundleDevelopmentRegion
8 | English
9 | CFBundleExecutable
10 | applet
11 | CFBundleIconFile
12 | applet
13 | CFBundleIdentifier
14 | com.complexpoint.OpenFT3DocAtLine
15 | CFBundleInfoDictionaryVersion
16 | 6.0
17 | CFBundleName
18 | OpenFTDoc3AtLine
19 | CFBundlePackageType
20 | APPL
21 | CFBundleSignature
22 | aplt
23 | CFBundleURLTypes
24 |
25 |
26 | CFBundleURLName
27 | Links to FoldingText3 docs
28 | CFBundleURLSchemes
29 |
30 | ft3doc
31 |
32 |
33 |
34 | LSMinimumSystemVersionByArchitecture
35 |
36 | x86_64
37 | 10.6
38 |
39 | LSRequiresCarbon
40 |
41 | WindowState
42 |
43 | bundleDividerCollapsed
44 |
45 | bundlePositionOfDivider
46 | 0.0
47 | dividerCollapsed
48 |
49 | eventLogLevel
50 | 2
51 | name
52 | ScriptWindowState
53 | positionOfDivider
54 | 1183
55 | savedFrame
56 | 211 53 952 1434 0 0 2560 1577
57 | selectedTab
58 | result
59 |
60 |
61 |
62 |
--------------------------------------------------------------------------------
/utilities/CopyFTasTP.applescript:
--------------------------------------------------------------------------------
1 | property pTitle : "Copy from FoldingText in TASKPAPER format"
property pVer : "0.1"
property pAuthor : "Rob Trew @complexpoint on Twitter"
property pRepo : "https://github.com/RobTrew/txtquery-tools"
property pLicense : "MIT"
property pstrJS : "
2 |
3 |
4 | function(editor, options) {
5 |
6 | // HOW MANY TABS WILL TASKPAPER NEED FOR THIS LINE ?
7 | function nestLevel(oNode) {
8 | var lngLevel=0;
9 | while (oNode.parent) {
10 | lngLevel++;
11 | oNode = oNode.parent;
12 | }
13 | return lngLevel;
14 | }
15 |
16 | // GET THE SELECTED LINES
17 | var lstNodes = editor.selectedRange().nodesInRange(),
18 | lstLines=[], varNode, strLine, dctTags, lstTags, varTag, strValue;
19 |
20 | // AND ADJUST TAB PREFIXES AND COLON SUFFIXES/INFIXES (BEFORE TAGS)
21 | lstNodes.forEach(function (varNode) {
22 | if (varNode.type() !== 'heading')
23 | strLine = varNode.line().trim();
24 | else {
25 | // INSERT A COLON (BEFORE ANY TAGS) TO MARK EACH HASH HEADING AS A TP PROJECT
26 | strLine = varNode.text() + ': ';
27 | dctTags = varNode.tags(); lstTags = [];
28 | for (varTag in dctTags) {
29 | strValue = dctTags[varTag];
30 | if (strValue) lstTags.push(['@',varTag,'(',strValue,')'].join(''));
31 | else lstTags.push('@' + varTag);
32 | }
33 | if (lstTags.length) strLine += lstTags.join(' ');
34 | }
35 |
36 | // PREPEND EACH LINE WITH THE NUMBER OF TABS THAT MATCHES THE NESTING LEVEL
37 | lstLines.push([Array(nestLevel(varNode)).join('\\t'), strLine].join(''));
38 | });
39 | return lstLines.join('\\n');
40 | }
41 |
42 | "
on run
set varResult to missing value
tell application "FoldingText"
set lstDocs to documents
if lstDocs ≠ {} then
tell item 1 of lstDocs to set varResult to (evaluate script pstrJS)
set the clipboard to varResult
end if
end tell
return varResult
end run
--------------------------------------------------------------------------------
/utilities/emotime.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | # Author: Rob Trew, https://github.com/RobTrew/txtquery-tools
3 | # Ver: 0.2
4 | # Gets emoji clockface (stdout|clipboard) with specified time (to nearest preceding half hour)
5 | # Call at command line with *on or two* integer parameters ($1 for hours, $2 for minutes)
6 | # e.g. chmod +x emotime.sh; emotime.sh 16 30
7 |
8 | # As this is a lossy representation, and optimism can prove double-edged, it operates in two modes:
9 | # Specified time: (to nearest *preceding* half hour) (don't show appointments as later than they are)
10 | # System time: (to nearest *following* half hour) (don't overstate how much sand remains in the glass)
11 |
12 | HRS=$1; MINS=$2
13 | ERRFORWARD=false #(if current time err forward, if scheduling, err earlier)
14 | if [[ -z $HRS ]]; then HRS=$(date +"%I"); ERRFORWARD=true; fi
15 | if [[ -z $MINS ]]; then MINS=$(date +"%M"); ERRFORWARD=true; fi
16 | JSC="/System/Library/Frameworks/JavaScriptCore.framework/Versions/A/Resources/jsc"
17 | EMOTIME=$("$JSC" -e "
18 | function emoTime(dteJS) {
19 | var lngBase=0x1F54F, lngHour=(dteJS.getHours() % 12), lngMins=dteJS.getMinutes(),
20 | iHourCode, iFullCode;
21 | if (lngHour) iHourCode=lngBase+lngHour; else iHourCode=lngBase+12;
22 |
23 | // Note: any second offset of 12 takes us to the block of corresponding half hour icons
24 | if ($ERRFORWARD) {
25 | if (lngMins >= 45) { // move on at quarter to and quarter past
26 | iFullCode=iHourCode+1;
27 | } else if (lngMins >= 15) {
28 | iFullCode=iHourCode+12; // jump to matching half hour glyph
29 | } else iFullCode=iHourCode;
30 | } else {
31 | // only move on at the full half hour
32 | if (lngMins >= 30) iFullCode=iHourCode+12; else iFullCode=iHourCode;
33 | }
34 | return asUnicode(iFullCode);
35 | }
36 |
37 | function asUnicode(c) {
38 | var lngClear = c - 0x10000;
39 | return String.fromCharCode( (lngClear >> 10) + 0xD800) +
40 | String.fromCharCode( (lngClear & 0x3FF) + 0xDC00);
41 | }
42 | dteJS = new Date(); dteJS.setHours($HRS, $MINS);
43 | print(emoTime(dteJS));")
44 | echo "$EMOTIME"
45 | echo "$EMOTIME" | pbcopy
46 |
--------------------------------------------------------------------------------
/copy as Markdown/safariCopyAsHTML.applescript:
--------------------------------------------------------------------------------
1 | // Yosemite JXA (Javascript for Automation) Copy As MD for Safari
2 | // Requires a copy **in the same folder as this script**
3 | // of html2text.py, originally contributed by Aaron Swartz z''l
4 | // [html2text.py](https://github.com/aaronsw/html2text)
5 | //
6 | function run() {
7 | /*jshint multistr: true */
8 |
9 | //var dct = {
10 | // title: "Copy as Markdown (for Safari)",
11 | // ver: "0.2",
12 | // description: "Runs HTML of Safari selection through html2text.py",
13 | // author: "RobTrew copyright 2014",
14 | // license: "MIT",
15 | // site: "https://github.com/RobTrew/txtquery-tools"
16 | //};
17 |
18 | // Compacted string of simple .js code for copying Safari selection as HTML
19 | var strFnHTMLSeln = "(function (){var c=window.getSelection(),\
20 | d=c.rangeCount,a;if(d){a=document.createElement('div');\
21 | for(var b=0;b> 10) + 0xD800) +
41 | String.fromCharCode((lngClear & 0x3FF) + 0xDC00);
42 | }
43 | dteJS = new Date($YEAR, $(($MONTH-1)), $DAY);
44 | print(emoMoon(dteJS));")
45 | echo "$EMOMOON"
46 | echo "$EMOMOON" | pbcopy
--------------------------------------------------------------------------------
/Yosemite Javascript XQuery demo/readme.md:
--------------------------------------------------------------------------------
1 | ### Custom perspectives across several files using NSXML XQuery from Javascript
2 | #### ( Simple demo )
3 |
4 | XQuery is now directly accessible to OS X 10.10 scripting.
5 |
6 | It provides a very flexible way of generating grouped and sub-grouped reports across a set of text files in HTML OPML or other XML formats, either generated automatically through a Hazel process from tagged MD or TaskPaper files, or as the native format of a preferred outlining and tagging application.
7 |
8 | [This script](./QueryAFolderOfOPMLFiles.applescript) (with the [folder of sample OPML files](./SampleFolder) on which it runs) provides a simple demo of a generic approach.
9 |
10 | ##### Installation and use
11 | - Copy the sample OPML files in SampleFolder to a folder on your system,
12 | - launch Brett Terpstra's [Marked 2](http://marked2app.com),
13 | - and run the QueryAFolderOfOPMLFiles script.
14 |
15 | > Note that it's a JXA Javascript.
16 | > In Yosemite Script Editor you will need to choose 'Javascript' rather than 'Applescript' from the top left pull-down
17 |
18 |
19 | When the script throws up a `choose folder` dialog, choose the folder containing the set of tagged OPML files
20 |
21 | ( These files could be exported from FoldingText @key(value) MD, or from OO3 columnar outlines, perhaps automatically by something like Hazel )
22 |
23 | ##### Output
24 | You will be offered a menu of custom perspectives, defined in the syntax of OS X 10.10's native NSXML XQuery 1.0.
25 |
26 | 
27 |
28 | The results will be displayed in [Marked 2](http://marked2app.com).
29 |
30 | 
31 |
32 | 
33 |
34 |
35 | ##### References
36 |
37 | - [XQuery/FLWOR Expression](http://en.wikibooks.org/wiki/XQuery/FLWOR_Expression)
38 | - [XQuery – Search Across a Variety of XML Data](http://shop.oreilly.com/product/9780596006341.do)
39 | - [XQuery 1.0](http://www.w3.org/TR/xquery/)
40 |
41 | - [NSXMLNode.objectsForQuery](https://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Classes/NSXMLNode_Class/index.html#//apple_ref/occ/instm/NSXMLNode/objectsForXQuery:error:)
42 |
43 |
44 |
--------------------------------------------------------------------------------
/filtering in the editor/tagsToggleHideFocus-minjs.applescript:
--------------------------------------------------------------------------------
1 | function run(){function v(e,x){var f=e.tree(),w=f.tags().sort(),b,a=[],h,c,d,m=0;b=0;for(var k=x.filtered,l=w.length,g=0;g 2) {
46 | strURL += ('?find=' + strText);
47 | }
48 |
49 | if (lngLine) {
50 | strURL += ('?line=' + lngLine.toString());
51 | }
52 |
53 | if (lngStartOffset) {
54 | if (lngEndOffset) {
55 | if (lngStartOffset !== lngEndOffset) {
56 | strURL += ('?startoffset=' + lngStartOffset.toString());
57 | strURL += ('?endoffset=' + lngEndOffset.toString());
58 | }
59 | }
60 |
61 | }
62 |
63 | return encodeURI(strURL);
64 | }
65 |
66 | "
on run
set varResult to missing value
tell application "TaskPaper"
set lstDocs to documents
if lstDocs ≠ {} then
set oDoc to item 1 of lstDocs
tell oDoc
set strPath to POSIX path of ((file of it) as alias)
set strURL to (evaluate script pstrJS with options {docpath:strPath})
set the clipboard to strURL
display notification "tp3doc:// link copied ..."
end tell
end if
end tell
return strURL
end run
--------------------------------------------------------------------------------
/filtering in the editor/FilterOnTagsMenu.applescript:
--------------------------------------------------------------------------------
1 | property pTitle : "Filter FT on chosen tags"
property pVer : "0.1"
property pAuthor : "Copyright (c) 2014 Robin Trew"
property pLicense : "MIT - see full text to be included in ALL copies at https://github.com/RobTrew/txtquery-tools
2 |
3 | (FoldingText is Copyright (c) 2014 Jesse Grosjean)
4 | "
property pUse : "
5 |
6 | Filters on all tags chosen from a menu.
7 |
8 | (For multiple selections in the menu, hold down the ⌘ command key)
9 |
10 | To include ancestors of the tagged lines:
11 | edit precOptions below to {axis:'///'}
12 |
13 | To exclude ancestors:
14 | edit precOptions below to {axis:'//'}
15 | "
property precOptions : {axis:"//"} -- or axis {"///"} to include ancestors of tagged lines
property pstrJS : "
16 | function(editor, options) {
17 |
18 | var lstSeldTags = options.tagset,
19 | strPath = '///*',
20 | lngTags, i;
21 |
22 | lngTags = lstSeldTags.length;
23 | if (lngTags) {
24 | strPath = options.axis
25 | if (lngTags < 2)
26 | strPath += ('@' + lstSeldTags[0]);
27 | else {
28 | strPath += '(';
29 | for (i=lngTags; i--;) {
30 | strPath += ('@' + lstSeldTags[i] + ' or ');
31 | }
32 | strPath = strPath.substr(0, strPath.length -4) + ')';
33 | }
34 | }
35 | editor.setNodePath(strPath);
36 | return strPath;
37 | }
38 |
39 | "
on run
set varResult to missing value
tell application "FoldingText"
set lstDocs to documents
if lstDocs ≠ {} then
tell item 1 of lstDocs
set lstTags to my ChooseTags(it)
if lstTags ≠ missing value then
set varResult to (evaluate script pstrJS with options precOptions & {tagset:lstTags})
else
evaluate script "function (editor) {editor.setNodePath('///*')}"
end if
end tell
end if
end tell
return varResult
end run
on ChooseTags(oDoc)
tell application "FoldingText"
tell oDoc to set lstTags to evaluate script "function(editor) {var lstTags = editor.tree().tags(false); lstTags.sort(); return lstTags;}"
activate
if lstTags ≠ {} then
set varChoice to choose from list lstTags with title pTitle & tab & pVer with prompt ¬
"Hold down ⌘ for multiple selections" & linefeed & linefeed & "Choose tags: " default items {item 1 of lstTags} ¬
OK button name "OK" cancel button name "Cancel" with empty selection allowed and multiple selections allowed
if varChoice = false then return missing value
return varChoice
else
return {}
end if
end tell
end ChooseTags
--------------------------------------------------------------------------------
/utilities/Italic.kmmacros:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Activate
7 | Normal
8 | IsActive
9 |
10 | Macros
11 |
12 |
13 | Actions
14 |
15 |
16 | DisplayKind
17 | None
18 | IsActive
19 |
20 | IsDisclosed
21 |
22 | MacroActionType
23 | ExecuteAppleScript
24 | Path
25 |
26 | Text
27 | property pstrJS : "
28 | function(editor) {
29 | editor.toggleSelectionFormatting(editor, '*');
30 | }
31 | "
32 | tell application "FoldingText"
33 | set lstDocs to documents
34 | if lstDocs ≠ {} then tell item 1 of lstDocs to (evaluate script pstrJS)
35 | end tell
36 | TimeOutAbortsMacro
37 |
38 | TrimResults
39 |
40 | TrimResultsNew
41 |
42 | UseText
43 |
44 |
45 |
46 | IsActive
47 |
48 | ModificationDate
49 | 428973401.487064
50 | Name
51 | Italic
52 | Triggers
53 |
54 |
55 | FireType
56 | Pressed
57 | KeyCode
58 | 34
59 | MacroTriggerType
60 | HotKey
61 | Modifiers
62 | 256
63 |
64 |
65 | UID
66 | 25CB5F49-F559-4B82-9F28-533CA65C8BBC
67 |
68 |
69 | Name
70 | FT 2
71 | Targeting
72 |
73 | Targeting
74 | Included
75 | TargetingApps
76 |
77 |
78 | BundleIdentifier
79 | com.foldingtext.paddle.FoldingText
80 | Name
81 | FoldingText
82 | NewFile
83 | /Applications/FoldingText.app
84 |
85 |
86 |
87 | UID
88 | ABCDA594-1101-4BB2-B211-DE343A76E2D5
89 |
90 |
91 |
92 |
--------------------------------------------------------------------------------
/ftdoc url scheme and FTCopyAsURL/FTCopyAsURL.applescript:
--------------------------------------------------------------------------------
1 | property pTitle : "Copy FT selection as ftdoc:// url"
property pVer : "0.04"
property pAuthor : "Rob Trew"
property pDescription : "
2 |
3 | Copies the selected text in FoldingText as an ftdoc:// URL
4 | linking back to the current document, filter state,
5 | and (if still identifiable by nodepath, search string or line number), selection.
6 |
7 | (Uses the ftdoc:// url-scheme - registered and handled by the OpenFTDocAtLine.app applescript app bundle)
8 |
9 | "
property pstrJS : "
10 |
11 | function(editor, options) {
12 |
13 | var libNodePath = require('ft/core/nodepath').NodePath,
14 | libPasteboard = require('ft/system/pasteboard').Pasteboard,
15 | libNotification = require('ft/system/notificationcenter').NotificationCenter,
16 | tree=editor.tree(),
17 |
18 | rngSeln = editor.selectedRange(),
19 | oFirstNode = rngSeln.startNode,
20 | dctStartOffset = rngSeln.startLineCh(),
21 | dctEndOffset = rngSeln.endLineCh(),
22 |
23 | strNodePath = editor.nodePath().toString(),
24 | strSelnPath = libNodePath.calculateMinNodePath(oFirstNode),
25 | strDocPath=options.docpath,
26 | strURL='', strText,
27 | strEncoded,
28 |
29 | lngLine = dctStartOffset.line,
30 | lngStartOffset=dctStartOffset.ch,
31 | lngEndOffset=-1,
32 | lnPosn;
33 |
34 |
35 |
36 | if (dctEndOffset.line === lngLine) {
37 | lngEndOffset = dctEndOffset.ch;
38 | }
39 | strURL='ftdoc://' + strDocPath;
40 |
41 | if (strNodePath !== '///*') {
42 | strURL += ('?nodepath=' + strNodePath);
43 | }
44 | if (strSelnPath.indexOf('@id') < 0) {
45 | strURL += ('?selnpath=' + strSelnPath);
46 | }
47 |
48 | strText = oFirstNode.text();
49 | if (strText.length > 2) {
50 | strURL += ('?find=' + strText);
51 | }
52 |
53 | if (lngLine) {
54 | strURL += ('?line=' + lngLine.toString());
55 | }
56 |
57 | if (lngStartOffset) {
58 | if (lngEndOffset) {
59 | if (lngStartOffset !== lngEndOffset) {
60 | strURL += ('?startoffset=' + lngStartOffset.toString());
61 | strURL += ('?endoffset=' + lngEndOffset.toString());
62 | }
63 | }
64 |
65 | }
66 |
67 | strEncoded=encodeURI(strURL);
68 | libPasteboard.writeString(strEncoded);
69 | libNotification.deliverNotification('ftdoc:// link copied',
70 | '(for current selection and filter state)', oFirstNode.text());
71 | return strEncoded;
72 | }
73 |
74 | "
on run
set varResult to missing value
tell application "FoldingText"
set lstDocs to documents
if lstDocs ≠ {} then
set oDoc to item 1 of lstDocs
tell oDoc
set strPath to POSIX path of ((file of it) as alias)
set strURL to (evaluate script pstrJS with options {docpath:strPath})
end tell
end if
end tell
return strURL
end run
--------------------------------------------------------------------------------
/perspectives.ftplugin/Example TXTQUERY.sh from KM.kmmacros:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Activate
7 | Normal
8 | IsActive
9 |
10 | Macros
11 |
12 |
13 | Actions
14 |
15 |
16 | IsActive
17 |
18 | IsDisclosed
19 |
20 | MacroActionType
21 | SetVariableToText
22 | Text
23 | -m
24 | Variable
25 | TXTQUERY_SWITCHES
26 |
27 |
28 | DisplayKind
29 | Window
30 | IsActive
31 |
32 | IsDisclosed
33 |
34 | MacroActionType
35 | ExecuteShellScript
36 | Path
37 | /Users/robintrew/Desktop/txtquery025.sh
38 | Text
39 | #!/bin/bash
40 |
41 | # A shell run by tools like KeyBoard Maestro, LaunchBar, Alfred etc may not pick up the user's bash paths
42 | if [[ ":$PATH:" != *":/usr/local/bin:"* ]]; then
43 | export PATH=$PATH:/usr/local/bin
44 | fi
45 |
46 | # Also ensure that the locale is a UTF-8 setting
47 | if [[ "$LC_CTYPE" != *"UTF-8"* ]]; then
48 | export LC_CTYPE="UTF-8"
49 | fi
50 |
51 | TXTQUERYPATH="$HOME/Library/Application Support/FoldingText/Plug-Ins/perspectives.ftplugin/txtquery.sh"
52 | cd "$(dirname "$TXTQUERYPATH")"
53 | chmod +x "$TXTQUERYPATH" #only needed once, if at all
54 |
55 |
56 | echo "$("$TXTQUERYPATH" $KMVAR_TXTQUERY_SWITCHES)"
57 | TimeOutAbortsMacro
58 |
59 | TrimResults
60 |
61 | TrimResultsNew
62 |
63 | UseText
64 |
65 |
66 |
67 | IsActive
68 |
69 | ModificationDate
70 | 429232747.86864299
71 | Name
72 | Example: TXTQUERY.sh from KM
73 | Triggers
74 |
75 |
76 | FireType
77 | Pressed
78 | KeyCode
79 | 17
80 | MacroTriggerType
81 | HotKey
82 | Modifiers
83 | 6400
84 |
85 |
86 | UID
87 | 2C37DC07-3D11-45B9-84E3-ED76AA1E9A15
88 |
89 |
90 | Name
91 | Global Macro Group
92 | UID
93 | B8D29C96-172A-44B1-A9DD-75E509D56722
94 |
95 |
96 |
97 |
--------------------------------------------------------------------------------
/utilities/SelectedMailToFTInbox.applescript:
--------------------------------------------------------------------------------
1 | property pTitle : "Selected Mail.app msg to FT Inbox"
property pVer : "0.2"
property pAuthor : "Rob Trew Twitter: @complexpoint"
-- EDIT THE FOLLOWING DETAILS TO SET THE BEHAVIOUR OF THE SCRIPT
property pblnAppendToFile : false -- (set to true if you simply want to append to the end of a named text file)
property pblnAddToTop : true -- (if adding to # Inbox section, add at top or end ?)
property pstrFilePath : "$HOME/Library/Application Support/Notational Velocity/Inbox.txt"
property pstrNodePath : "/Inbox" -- (Assumes that inbox is a top level heading, if it exists)
property precOptions : {inboxpath:pstrNodePath, top:pblnAddToTop}
property pstrJS : "
2 |
3 | function(editor, options) {
4 | var oTree = editor.tree(),
5 | lstInbox = oTree.evaluateNodePath(options.inboxpath), oInbox,
6 | strText, lstChiln, strMsg=options.msg, lstLines = strMsg.split('\\n'),
7 | lngLines = lstLines.length, i, oFirstChild=null, blnTop = options.top;
8 |
9 | if (lngLines) {
10 | // CHECK THAT WE HAVE AN INBOX (CREATING ONE IF NECESSARY)
11 | if (lstInbox.length) {
12 | oInbox = lstInbox[0];
13 | } else {
14 | oInbox = oTree.createNode('# Inbox');
15 | oTree.appendNode(oInbox);
16 | }
17 | oTree.ensureClassified();
18 | if (oInbox.hasChildren()) {
19 | oFirstChild = oInbox.children()[0];
20 | }
21 | // ADD NEW LINES EITHER AT START OR END OF INBOX
22 | if (blnTop && oFirstChild) {
23 | for (i=0; i> " & quoted form of strPath
do shell script strCMD
else
-- OR OPEN AS DOC IN FT AND ADD TO AN INBOX SECTION (IF property pblnAppendToFile : FALSE)
set recOptions to {msg:strMD} & precOptions
tell application "FoldingText"
set oDoc to open strPath
tell oDoc to set varResult to (evaluate script pstrJS with options recOptions)
end tell
end if
end if
end run
on MailSelnAsMd()
tell application "Mail"
activate
set lstText to {}
repeat with refMsg in (selection as list)
tell (contents of refMsg)
set strLine to "- [" & sender & "]() [" & subject
set end of lstText to strLine & "](message://%3c" & message id & "%3e)"
end tell
end repeat
set {dlm, my text item delimiters} to {my text item delimiters, linefeed}
set strTxt to lstText as string
set my text item delimiters to dlm
return strTxt
end tell
end MailSelnAsMd
--------------------------------------------------------------------------------
/utilities/OpeniThoughtsMapinMarked.applescript:
--------------------------------------------------------------------------------
1 | property pTitle : "Open active iThoughtsX map in Marked 2"
property pVer : "0.5"
property pblnPositionWindows : true -- Set this to false to disable the window positioning at the end of the script
property pstrMarked : "Marked"
property pstrThoughts : "iThoughtsX"
property rLeftProportion : 1 / 4 -- what horizontal proportion of the screen for the app to the left ?
property plstApps : {pstrMarked, pstrThoughts} -- (first app to left, swap order to swap app positions)
-- Applescript properties persist between calls in compiled .scpt files
-- This makes the script faster after the first use (it can skip display resolution detection)
-- (but recompile from text and resave if you switch to a display with a different resolution)
property pX : missing value
property pY : missing value
tell application "System Events"
-- OPEN CURRENT iThoughtsX MAP IN MARKED 2
set lstProc to application processes where name contains pstrThoughts
if lstProc is not equal to {} then
try
set winThoughts to front window of item 1 of lstProc
on error
return
end try
set strURL to value of (attribute "AXDocument" of winThoughts)
do shell script "open -a Marked\\ 2 " & quoted form of strURL
-- RESIZE AND REPOSITION WINDOWS, IF REQUIRED
if pblnPositionWindows then -- ( Edit boolean value at start of script )
-- AVAILABLE CANVAS
set {lngWidth, lngHeight} to my displayResoln()
set lngAppHeight to lngHeight - 22
-- POSITION OF EDGE BETWEEN APPS (MEASURED FROM LEFT OF SCREEN)
set lngLeft to (lngWidth * rLeftProportion) as integer
-- LEFT APP WINDOW
set lstLeftProc to {}
set lstLeftProc to application processes where name contains (item 1 of plstApps)
if lstLeftProc is not equal to {} then
try
set winLeft to front window of (item 1 of lstLeftProc)
tell winLeft to set {position, size} to {{0, 22}, {lngLeft, lngAppHeight}}
end try
end if
-- RIGHT APP WINDOW
set lstRightProc to {}
set lstRightProc to application processes where name contains (item 2 of plstApps)
if lstRightProc is not equal to {} then
try
set winRight to front window of (item 1 of lstRightProc)
tell winRight to set {position, size} to {{lngLeft, 22}, {(lngWidth - lngLeft), lngAppHeight}}
end try
end if
end if
tell application "Marked 2" to activate
tell application "iThoughtsX" to activate
end if
end tell
on displayResoln()
if (pX is missing value) or (pY is missing value) then
set {dlm, my text item delimiters} to {my text item delimiters, "Resolution"}
set lstDisplays to text items of (do shell script "system_profiler SPDisplaysDataType")
repeat with i from 2 to length of lstDisplays
set strLine to item i of lstDisplays
if strLine contains "Main Display: Yes" then exit repeat
end repeat
set my text item delimiters to space
set lstParts to text items of strLine
set my text item delimiters to dlm
set {strX, strY} to {item 2, item 4} of lstParts
set {pX, pY} to {strX as integer, strY as integer}
end if
return {pX, pY}
end displayResoln
--------------------------------------------------------------------------------
/utilities/OpenFTDocinMarked.applescript:
--------------------------------------------------------------------------------
1 | property pTitle : "Open active FoldingText document in Marked 2"
2 | property pVer : "0.5"
3 |
4 | property pblnPositionWindows : true -- Set this to false to disable the window positioning at the end of the script
5 |
6 | -- Applescript properties persist between calls in compiled .scpt files
7 | -- This makes the script faster after the first use (it can skip display resolution detection)
8 | -- (but recompile from text and resave if you switch to a display with a different resolution)
9 | property pX : missing value
10 | property pY : missing value
11 |
12 | property pstrMarked : "Marked"
13 | property pstrFT : "FoldingText"
14 |
15 | property rLeftProportion : 1 / 4 -- what horizontal proportion of the screen for the app to the left ?
16 | property plstApps : {pstrMarked, pstrFT} -- (first app to left, second to right: adjust as preferred)
17 |
18 | tell application "System Events"
19 | -- OPEN CURRENT DOC IN MARKED 2
20 | set lstProc to application processes where name contains pstrFT
21 | if lstProc is not equal to {} then
22 | try
23 | set winFT to front window of item 1 of lstProc
24 | on error
25 | return
26 | end try
27 | set strURL to value of (attribute "AXDocument" of winFT)
28 |
29 | do shell script "open -a Marked\\ 2 " & quoted form of strURL
30 |
31 | -- RESIZE AND REPOSITION WINDOWS, IF REQUIRED
32 |
33 | if pblnPositionWindows then -- ( Edit boolean value at start of script )
34 |
35 | -- AVAILABLE CANVAS
36 | set {lngWidth, lngHeight} to my displayResoln()
37 | set lngAppHeight to lngHeight - 22
38 |
39 | -- POSITION OF EDGE BETWEEN APPS (MEASURED FROM LEFT OF SCREEN)
40 | set lngLeft to (lngWidth * rLeftProportion) as integer
41 |
42 | -- LEFT APP WINDOW
43 | set lstLeftProc to {}
44 | set lstLeftProc to application processes where name contains (item 1 of plstApps)
45 | if lstLeftProc is not equal to {} then
46 | try
47 | set winLeft to front window of (item 1 of lstLeftProc)
48 | tell winLeft to set {position, size} to {{0, 22}, {lngLeft, lngAppHeight}}
49 | end try
50 | end if
51 |
52 | -- RIGHT APP WINDOW
53 | set lstRightProc to {}
54 | set lstRightProc to application processes where name contains (item 2 of plstApps)
55 | if lstRightProc is not equal to {} then
56 | try
57 | set winRight to front window of (item 1 of lstRightProc)
58 | tell winRight to set {position, size} to {{lngLeft, 22}, {lngWidth - lngLeft, lngAppHeight}}
59 | end try
60 | end if
61 | end if
62 | end if
63 | end tell
64 |
65 | on displayResoln()
66 | if (pX is missing value) or (pY is missing value) then
67 | set {dlm, my text item delimiters} to {my text item delimiters, "Resolution"}
68 | set lstDisplays to text items of (do shell script "system_profiler SPDisplaysDataType")
69 |
70 | repeat with i from 2 to length of lstDisplays
71 | set strLine to item i of lstDisplays
72 | if strLine contains "Main Display: Yes" then exit repeat
73 | end repeat
74 | set my text item delimiters to space
75 | set lstParts to text items of strLine
76 | set my text item delimiters to dlm
77 | set {strX, strY} to {item 2, item 4} of lstParts
78 | set {pX, pY} to {strX as integer, strY as integer}
79 | end if
80 | return {pX, pY}
81 | end displayResoln
--------------------------------------------------------------------------------
/utilities/FT2CSV.applescript:
--------------------------------------------------------------------------------
1 | property pTitle : "Copy front FoldingText 2 document as CSV or TSV"
property pVer : "0.2"
property pAuthor : "Rob Trew Twitter: @complexpoint"
property pDescription : "
2 |
3 | Copies contents of front FoldingText document to the clipboard as CSV or TSV
4 | (tab separated values)
5 |
6 | Edit pstrDelim below to specify commas or tabs
7 |
8 | (NOTE: a tab-delimited TSV version can be pasted straight into Excel,
9 | CSV needs to be pasted into a text file, and then opened in Excel)
10 |
11 | FORMAT:
12 | One spreadsheet column for each level of outline indentation, and
13 | One spreadsheet column for each type of @key(value) tag in the document
14 |
15 | The key of @key(value) is used as the column heading,
16 | and the value is placed in the spreadsheet cells
17 |
18 | DATES:
19 | Excel automatically recognises yyyy-mm-dd
20 | and yyyy-mm-dd hh:mm as datetime strings, and converts them accordingly.
21 |
22 | @due(2015-06-01 14:00) will become an excel date in a column with header 'Due'
23 |
24 | "
property pstrTab : tab
property pstrComma : ","
-- SPECIFY FIELD DELIMITER BY EDITING THE VALUE OF PSTRDELIM HERE
property pstrDelim : pstrTab
-- VALUE TO EXPORT FOR SIMPLE IMPLICIT BOOLEANS LIKE @waiting WHICH DONT HAVE A BRACKETED VALUE
property pstrBoolTrue : "1"
property precOptions : {delimiter:pstrDelim, booltrue:pstrBoolTrue}
-- NOTE: FIELDS CONTAINING THE DELIMITER WILL BE QUOTED
property pstrJS : "
25 | function(editor, options) {
26 |
27 | function maxdepth(node) {
28 | // DEEPEST LEVEL IN THE FOLDINGTEXT OUTLINE
29 | var lngChiln = 0, lstChiln=[],
30 | lngMax = 0, lngDepth = 0;
31 |
32 | if (node.hasChildren()) {
33 | lstChiln = node.children();
34 | for (var i = lstChiln.length; i --;) {
35 | lngDepth = maxdepth(lstChiln[i]) + 1;
36 | if (lngDepth > lngMax) lngMax = lngDepth;
37 | }
38 | }
39 | return lngMax;
40 | }
41 |
42 | function nestLevel(oNode) {
43 | // OUTLINE LEVEL OF THIS NODE
44 | var oParent = oNode.parent;
45 | if (!oNode.parent) {
46 | return -1;
47 | } else return nestLevel(oParent) +1;
48 | }
49 |
50 | var strDelim = options.delimiter,
51 | strBool = options.booltrue,
52 | oTree=editor.tree(),
53 | lngLevels = maxdepth(oTree.root),
54 | lstTags = oTree.tags(true).sort(),
55 | lngTags = lstTags.length,
56 | lngCols=lngLevels+lngTags,
57 | lstCols=new Array(lngCols),
58 | lstRecord, strTag, iTag, iCol,
59 | lstRows=[], strRow, strValue;
60 |
61 | // CREATE A HEADER (ONE COLUMN FOR EACH OUTLINE LEVEL, AND ONE COLUMN FOR EACH TAG)
62 | lstRecord = lstCols.slice(0);
63 | for (iCol=lngLevels; iCol--;) {
64 | lstRecord[iCol] = 'Level ' + (iCol+1).toString();
65 | }
66 | for (iTag=lngTags; iTag--;) {
67 | strTag=lstTags[iTag]
68 | lstRecord[lngLevels+iTag] = strTag[0].toUpperCase() + strTag.slice(1).toLowerCase();
69 | }
70 | lstRows.push(lstRecord.join('\\t'));
71 |
72 | // GATHER THE DATA ROWS
73 | oTree.nodes().forEach(function (oNode) {
74 | lstRecord = lstCols.slice(0);
75 | lstRecord[nestLevel(oNode)] = oNode.text();
76 | for (iTag=lngTags;iTag--;) {
77 | strTag=lstTags[iTag];
78 | if (oNode.hasTag(strTag)) {
79 | strValue=oNode.tag(strTag);
80 | if (strValue) {
81 | if (strValue.indexOf(strDelim) !== -1) {
82 | strValue='\"' + strValue + '\"';
83 | }
84 | } else strValue = strBool;
85 | lstRecord[lngLevels+iTag] = strValue;
86 | }
87 | }
88 | strRow = lstRecord.join(strDelim);
89 | lstRows.push(strRow);
90 | });
91 |
92 | return lstRows.join('\\n');
93 | }
94 | "
on run
set varResult to missing value
tell application "FoldingText"
set lstDocs to documents
if lstDocs ≠ {} then
tell item 1 of lstDocs to set varResult to (evaluate script pstrJS with options precOptions)
set the clipboard to varResult
end if
end tell
return varResult
end run
--------------------------------------------------------------------------------
/filtering in the editor/ArchiveTagsMenu.applescript:
--------------------------------------------------------------------------------
1 | property pTitle : "Archive chosen tag-types to matching section"
property pVer : "0.1"
property pAuthor : "Copyright (c) 2014 Robin Trew"
property pLicense : "MIT - see full text to be included in ALL copies at https://github.com/RobTrew/txtquery-tools
2 |
3 | (FoldingText is Copyright (c) 2014 Jesse Grosjean)
4 | "
property pUse : "
5 |
6 | Archives all line tagged with a tag chosen from a menu,
7 | to a section '# Archive '.
8 |
9 | To change the affected tag, edit the tagname in property precOptions below this line.
10 |
11 | (if you comment out the precOptions line, the script will offer a menu,
12 | listing each type of tag found in the document )
13 | "
14 |
15 | -- INCLUDE A LINE LIKE THE FOLLOWING TO BY-PASS THE MENU AND CREATE A SCRIPT SPECIFIC TO ONE TAG TYPE
-- property precOptions : {archivetags:{"waiting"}}
-- property precOptions : {archivetags:{"cancelled"}}
property pstrJS : "
16 | function(editor) {
17 | // Skip any line already archived with an ancestor
18 | function rootsOnly(oTree, lstNodes) {
19 | var lstSeen = [], strID, oParent, lngNodes=lstNodes.length, oNode,i;
20 |
21 | nextnode: for (i=0; i Open Application Folder`
70 | - Copy the `.ftplugin` folder and its contents into the `Plug-Ins` sub-folder of the application folder
71 | - Close and restart the application
--------------------------------------------------------------------------------
/copy as Markdown/Copy as Markdown.kmmacros:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Activate
7 | Normal
8 | IsActive
9 |
10 | Macros
11 |
12 |
13 | Actions
14 |
15 |
16 | DisplayKind
17 | Variable
18 | IsActive
19 |
20 | IsDisclosed
21 |
22 | MacroActionType
23 | ExecuteShellScript
24 | Path
25 |
26 | Text
27 | osascript -l JavaScript '/Users/robintrew/txtquery-tools/copy as Markdown/safariCopyAsMDjs.scpt' 2> /dev/null
28 | TimeOutAbortsMacro
29 |
30 | TrimResults
31 |
32 | TrimResultsNew
33 |
34 | UseText
35 |
36 | Variable
37 | ClipResults
38 |
39 |
40 | Conditions
41 |
42 | ConditionList
43 |
44 |
45 | ConditionType
46 | Variable
47 | Variable
48 | ClipResults
49 | VariableConditionType
50 | IsNotEmpty
51 | VariableValue
52 | value
53 |
54 |
55 | ConditionListMatch
56 | All
57 |
58 | ElseActions
59 |
60 |
61 | IsActive
62 |
63 | IsDisclosed
64 |
65 | MacroActionType
66 | Notification
67 | SoundName
68 | Blow
69 | Subtitle
70 | (HTML access may not be allowed by website)
71 | Text
72 |
73 | Title
74 | Nothing copied ...
75 |
76 |
77 | IsActive
78 |
79 | IsDisclosed
80 |
81 | MacroActionType
82 | IfThenElse
83 | ThenActions
84 |
85 |
86 | IsActive
87 |
88 | IsDisclosed
89 |
90 | MacroActionType
91 | Notification
92 | SoundName
93 | Pop
94 | Subtitle
95 | Selection Copied as Markdown
96 | Text
97 | %Variable%ClipResults%
98 | Title
99 | Safari
100 |
101 |
102 | TimeOutAbortsMacro
103 |
104 |
105 |
106 | IsActive
107 |
108 | ModificationDate
109 | 437610601.50608599
110 | Name
111 | Copy as Markdown
112 | Triggers
113 |
114 |
115 | FireType
116 | Pressed
117 | KeyCode
118 | 8
119 | MacroTriggerType
120 | HotKey
121 | Modifiers
122 | 6400
123 |
124 |
125 | UID
126 | DA64481D-4C7D-4D63-BEB8-B0065B5CE452
127 |
128 |
129 | Name
130 | Safari
131 | UID
132 | 7522F7B8-A30C-4313-AC93-813DF667C99B
133 |
134 |
135 |
136 |
--------------------------------------------------------------------------------
/filtering in the editor/FilterOnAllSelectedTags.applescript:
--------------------------------------------------------------------------------
1 | property pTitle : "Filter FoldingText on all selected tags"
property pVer : "0.1"
property pAuthor : "Copyright (c) 2014 Robin Trew"
property pLicense : "MIT - see full text to be included in ALL copies at https://github.com/RobTrew/txtquery-tools
2 |
3 | (FoldingText is Copyright (c) 2014 Jesse Grosjean)
4 | "
property pUse : "
5 |
6 | Filters on all tags overlapping single or multiple selections.
7 |
8 | (For multiple selections in FoldingText, hold down the ⌘ command key)
9 |
10 | To include ancestors of the tagged lines:
11 | edit precOptions below to {axis:'///'}
12 |
13 | To exclude ancestors:
14 | edit precOptions below to {axis:'//'}
15 | "
property precOptions : {axis:"//"} -- or axis {"///"} to include ancestors of tagged lines
property pstrJS : "
16 | function(editor, options) {
17 |
18 | function selectedTags(editor) {
19 | // ALL TAGS OVERLAPPED BY ANY SINGLE OR MULTIPLE SELECTIONS
20 | var rngSeln, oNode, dctTagPosns,
21 | lstSeln, lstNodes, lstSelnPosns, lstSeldTags=[],
22 | lstNodeTags, lstTagStartEnd,
23 | strTag, blnSeln = editor.hasSelection(), i,j;
24 |
25 | if (blnSeln) {
26 | lstSeln = editor.selectedRanges();
27 | for (i=lstSeln.length; i--;) {
28 | rngSeln = lstSeln[i];
29 | lstNodes = rngSeln.nodesInRange();
30 | for (j=lstNodes.length; j--;) {
31 | oNode = lstNodes[j];
32 | // If the node has tags
33 | if (Object.keys(oNode.tags()).length) {
34 | dctTagPosns = tagPositions(oNode);
35 | lstSelnPosns = selnPositions(oNode, rngSeln);
36 |
37 | for (strTag in dctTagPosns) {
38 | // Unless we have already seen this tag
39 | if (lstSeldTags.indexOf(strTag) == -1) {
40 | if (overlap(dctTagPosns[strTag], lstSelnPosns))
41 | lstSeldTags.push(strTag);
42 | }
43 | }
44 | }
45 | }
46 | }
47 | }
48 | return lstSeldTags;
49 | }
50 |
51 | function tagPositions(oNode) {
52 | // START AND END OFFSETS OF EACH TAG IN THIS NODE
53 | var lstRuns = oNode.lineAttributedString()._attributeRuns,
54 | dctTagPosns = {}, oRun, oAttr, strTag, iFrom, k;
55 |
56 | for (k=lstRuns.length; k--;) {
57 | oRun = lstRuns[k];
58 | oAttr = oRun.attributes;
59 | if (oAttr.keyword == '@') {
60 | strTag = oAttr.tag;
61 | iFrom = oRun.location;
62 | dctTagPosns[tagKey(strTag)]=[iFrom, iFrom+strTag.length];
63 | }
64 | }
65 | return dctTagPosns;
66 | }
67 |
68 | function selnPositions(oNode, rngSeln) {
69 | // OFFSETS OF FIRST AND LAST SELECTED CHARS IN THIS NODE
70 | var iNodeEnd = oNode.line().length,
71 | iSelnStart = rngSeln.startOffset,
72 | iSelnLength = rngSeln.length(),
73 | iNodeAbsStart = oNode.lineTextStart(),
74 | iNodeAbsEnd = iNodeAbsStart + iNodeEnd,
75 | iSelnAbsStart = rngSeln.location(),
76 | iSelnAbsEnd = iSelnAbsStart + iSelnLength,
77 | iStart, iEnd;
78 |
79 | if (iSelnAbsStart < iNodeAbsStart) iStart = 0;
80 | else iStart = iSelnStart;
81 |
82 | if (iSelnAbsEnd > iNodeAbsEnd) iEnd = iNodeEnd;
83 | else iEnd =iSelnStart+iSelnLength;
84 |
85 | return [iStart, iEnd];
86 | }
87 |
88 | function overlap(lstA, lstB) {
89 | // NOT IF THIS ENDS BEFORE THAT STARTS,
90 | // OR STARTS AFTER THAT ENDS
91 | return !(lstA[1] < lstB[0] || lstA[0] > lstB[1]);
92 | }
93 |
94 | function tagKey(strKeyValueTag) {
95 | // JUST THE KEY PART OF A @key(value) OR @key TAG
96 | var strKey, iOpen = strKeyValueTag.indexOf('(');
97 |
98 | if (iOpen !== -1) strKey = strKeyValueTag.substring(1, iOpen);
99 | else strKey = strKeyValueTag.substring(1);
100 | return strKey;
101 | }
102 |
103 | var lstSeldTags = selectedTags(editor),
104 | strPath = '///*',
105 | lngTags, i;
106 |
107 | lngTags = lstSeldTags.length;
108 | if (lngTags) {
109 | strPath = options.axis
110 | if (lngTags < 2)
111 | strPath += ('@' + lstSeldTags[0]);
112 | else {
113 | strPath += '(';
114 | for (i=lngTags; i--;) {
115 | strPath += ('@' + lstSeldTags[i] + ' or ');
116 | }
117 | strPath = strPath.substr(0, strPath.length -4) + ')';
118 | }
119 | }
120 | editor.setNodePath(strPath);
121 | return strPath;
122 | }
123 |
124 | "
on run
set varResult to missing value
tell application "FoldingText"
set lstDocs to documents
if lstDocs ≠ {} then
tell item 1 of lstDocs
set varResult to (evaluate script pstrJS with options precOptions)
end tell
end if
end tell
return varResult
end run
--------------------------------------------------------------------------------
/utilities/cliptextcolors.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | # Author: Rob Trew, 2014
3 |
4 | # ver 0.2
5 |
6 | # SPECIFY DEFAULT MESSAGE COLOR MODEL, VALUE RANGES, CYCLE COUNT
7 |
8 | TRANSFORM_CLIPBOARD=1 #0 (or empty) to leave plain text version in clipboard, 1 to put RTF or 2 to put HTML in clipboard)
9 | MSG="abracadabracadabracadabracadabra"
10 | FONTFACE="Courier"
11 | FONTSIZE="4"
12 | SCHEME="DarkRainBow" # Choose a key from set of scheme names in 'var options' below, or add a scheme
13 |
14 | # TO USE:
15 | # 1. Copy some plain text into the clipboard
16 | # 2. Run this script
17 | # 3. Colored HTML spans for each character will be written to STDOUT
18 | # 4. if $TRANSFORM_CLIPBOARD (above) is non-zero, an RTF (=1) or HTML (=2) version will replace the plain text in the clipboard
19 |
20 | # Example:
21 |
22 | # 'BlackToRed' : {'model':'hsl', -- 'hsl' or 'rgb'
23 | # 'percent':[false, true, true], -- should the nth value of 3 be followed by '%' ?
24 | # p1:[255, 0], p2:[20, 100], p3:[20, 50], -- range of values for the nth of 3 integers to cycle through
25 | # cycles:2} -- how many Pi cycles ? 1=from start to end value 2=return to start value N=several cycles
26 |
27 | CLIPTEXT=$(pbpaste -Prefer txt)
28 | if [ ! -z "$CLIPTEXT" ]; then
29 | MSG="$CLIPTEXT"
30 | fi
31 |
32 | escape() {
33 | echo "$1" | sed "s/\([^[:alnum:]]\)/\\\\\1/g"
34 | }
35 |
36 | CLEAN=$(escape "$MSG")
37 |
38 | JSC="/System/Library/Frameworks/JavaScriptCore.framework/Versions/A/Resources/jsc"
39 | COLORSPANS=$("$JSC" -e "
40 |
41 | var options = {'msg':'$CLEAN', 'fontface':'$FONTFACE','fontsize':$FONTSIZE},
42 | dctPalette = {
43 | 'BlackToRed' : {'model':'hsl', 'percent':[false, true, true],
44 | p1:[0, 255], p2:[20, 100], p3:[20, 50], cycles:2},
45 | 'Gray' : {'model':'rgb', 'percent':[false, false, false],
46 | p1:[255, 40], p2:[255, 40], p3:[255, 40], cycles:2},
47 | 'RainBow' : {'model':'hsl', 'percent':[false, true, true],
48 | p1:[255, 0], p2:[100, 100], p3:[50, 50], cycles:2},
49 | 'DarkRainBow' : {'model':'hsl', 'percent':[false, true, true],
50 | p1:[255,0], p2:[0, 100], p3:[50, 50], cycles:2},
51 | 'RedPink' : {'model':'hsl', 'percent':[false, true, true],
52 | p1:[0, 0], p2:[100, 100], p3:[95, 50], cycles:2},
53 | 'RedGrey' : {'model':'hsl', 'percent':[false, true, true],
54 | p1:[0, 255], p2:[100, 12], p3:[50, 80], cycles:2},
55 | 'GreyRed' : {'model':'hsl', 'percent':[false, true, true],
56 | p1:[255, 0], p2:[12, 100], p3:[80, 50], cycles:2}
57 | },
58 | dctScheme=dctPalette['$SCHEME'];
59 |
60 | function colorSpans(options) {
61 | var strMsg = options.msg,
62 | lngChars = strMsg.length,
63 | nCycles = options.cycles * Math.PI,
64 | lstP1=options.p1,
65 | lstP2=options.p2,
66 | lstP3=options.p3,
67 | min1=lstP1[0], max1=lstP1[1],
68 | min2=lstP2[0], max2=lstP2[1],
69 | min3=lstP3[0], max3=lstP3[1],
70 | lstStart=[min1, min2, min3],
71 | lstFixed=[Math.round(min1).toString(), Math.round(min2).toString(), Math.round(min3).toString()],
72 | lstRange=[max1-min1, max2-min2, max3-min3], nRange,
73 | lstVal=[],
74 | strModel=options.model,
75 | lstPercent=options.percent,
76 | strVal='', lstSpan=[],lstHTML=[],
77 | nTheta, rPropn,
78 | i,j;
79 |
80 | for (i=0; i', strMsg.charAt(i),''];
97 |
98 | //and push this single character span onto the HTML list.
99 | lstHTML.push(lstSpan.join(''));
100 | }
101 | return '' + lstHTML.join('') + '';
102 | }
103 |
104 | for (var strKey in dctScheme) {
105 | options[strKey] = dctScheme[strKey];
106 | }
107 | print(colorSpans(options));
108 | ")
109 | echo "$COLORSPANS"
110 |
111 | if [[ ! -z $TRANSFORM_CLIPBOARD ]]; then
112 | if [ $TRANSFORM_CLIPBOARD -eq 1 ]; then
113 | echo "$COLORSPANS" | textutil -format html -convert rtf -inputencoding UTF-8 -stdin -stdout | pbcopy -Prefer rtf
114 | elif [ $TRANSFORM_CLIPBOARD -eq 2 ]; then
115 | echo "$COLORSPANS" | pbcopy
116 | fi
117 | fi
118 |
119 |
120 |
--------------------------------------------------------------------------------
/ftdoc3 url scheme/README.md:
--------------------------------------------------------------------------------
1 | ### Copy FoldingText for Atom selection as ft3doc:// link back to document and selected line
2 |
3 | A [Keyboard Maestro](http://www.keyboardmaestro.com/main/) macro:
4 |
5 | - [Copy ft3doc URL for selected line in FoldingText 3.kmmacros](./Copy%20ft3doc%20URL%20for%20selected%20line%20in%20FoldingText%203.kmmacros)
6 | - [Copy ft3doc URL for selected line in FoldingText 3.kmmacros.zip](./Copy%20ft3doc%20URL%20for%20selected%20line%20in%20FoldingText%203.kmmacros.zip)
7 |
8 | which copies a path back to the open [FoldingText 3 for Atom beta](http://jessegrosjean.gitbooks.io/foldingtext-for-atom-user-s-guide/content/) document, and to the currently selected line. (FT3 lines have unique and persistent ids which can be used as url link targets)
9 |
10 | The built-in [Atom](https://atom.io/) menu command: **Atom > Edit > Copy Path** copies a `file://` url which can be used as an argument to the **atom** command in the shell, but is not predictably handled by browsers or other applications, which may display a preview of the file, or open a Finder window to reveal it, but will not open a file and select the relevant line.
11 |
12 | This macro also uses **Atom > Edit > Copy Path**, but replaces the `file://` prefix with the custom `ft3doc://` which requires simple installation (see below) of a handler app (OpenFT3DocAtLine.app), which needs to be on your system, but only needs to be run once, to register `ft3doc://` as a known handler.
13 |
14 |
15 | ### Applications
16 | - As an external bookmark to a particular point in a document (for example from another app)
17 | - For use in cross-file perspectives (defined in XQuery) as a link back to the lines displayed by a query.
18 |
19 | ### Use
20 | - Install the KeyBoard Maestro macro
21 | - Select a line or phrase in FoldingText 3 for Atom
22 | - Run the macro with Ctrl Shift C
23 | - Paste the resulting `ft3doc://` url wherever you need it.
24 | - (Not that cross file and internal links withing FT3 can already be created by simple drag and Ctrl-drop)
25 |
26 | #### `ft3doc://`
27 | #### A url-scheme for opening a FoldingText 3 for Atom document at a specific line
28 | The `ft3doc://` url-scheme is registered and handled by an Applescript, [OpenFT3DocAtLine.app](./OpenFT3DocAtLine.app) [OpenFT3DocAtLine.app.zip](./OpenFT3DocAtLine.app.zip):
29 |
30 | ###### OpenFT3DocAtLine.app
31 | - Is a [simple applescript](Source%20and%20info.plist%20for%20OpenFT3DocAtLine/OpenFT3DocAtLine.applescript) saved as an [app bundle](./OpenFT3DocAtLine.app), and
32 | - contains an [Info.plist](Source%20and%20info.plist%20for%20OpenFT3DocAtLine/Info.plist) which registers `ft3doc://`
33 | - contains an open url handler which:
34 | - Opens a specified text document in [FoldingText 3 for Atom beta](http://jessegrosjean.gitbooks.io/foldingtext-for-atom-user-s-guide/content/)
35 | - selects the line specified by its unique id
36 | - and can contain further [query, hoisting and expansion switches](http://jessegrosjean.gitbooks.io/foldingtext-for-atom-user-s-guide/content/appendix_c_path_query_parameters.html)
37 |
38 | NB if you want to create `ftdoc3://` urls ‘by hand’ or with a script of your own, you will need to uri-encode the file path and any nodepath. There are various ways of doing this at the command line, or in an applescript, with something like:
39 |
40 | ```
41 | on encode(strPath)
42 | do shell script "python -c 'import sys, urllib as ul; print ul.quote(sys.argv[1])' " & quoted form of strPath
43 | end encode
44 | ```
45 |
46 | Easier, of course, in Javascript: `encodeURI()` for a whole link, or `encodeURIComponent()` for parts excluding the opening scheme name.
47 |
48 |
49 | #### Installation
50 |
51 | For the `ft3doc://` url scheme to be registered, [OpenFT3DocAtLine.app](./OpenFTDoc3AtLine.app) [OpenFT3DocAtLine.app.zip](./OpenFT3DocAtLine.app.zip) needs to be on your system, and needs to have been run at least once.
52 | To do this:
53 | - EITHER extract the copy from the [txtquery-tools](https://github.com/RobTrew/txtquery-tools) repository [zip file](https://github.com/RobTrew/txtquery-tools/archive/master.zip), and ctrl-click to allow the OS X Gate Keeper security system to run it
54 | - OR:
55 | - open the .applescript text version Applescript editor,
56 | - save as an .app bundle
57 | - Ctrl-click on the .app bundle to _Open Package Contents_
58 | - and replace the info.plist file with the version which declares the url-scheme
59 |
60 | [Repository .zip file](https://github.com/RobTrew/txtquery-tools/archive/master.zip)
61 |
62 | ##### Reference
63 | For an explanation of this approach to registering and handling a url with an applescript.app, and the info.plist in its bundle,
64 | See [http://www.macosxautomation.com/applescript/linktrigger/](http://www.macosxautomation.com/applescript/linktrigger/)
65 |
66 |
--------------------------------------------------------------------------------
/tp3doc url scheme and TP3CopyAsURL/README.md:
--------------------------------------------------------------------------------
1 | ### Copy TaskPaper selection as tp3doc:// link back to document, line, selection and filter state
2 |
3 | The [TP3CopyAsURL](./TP3CopyAsURL.applescript) applescript copies the currently selected text position in [TaskPaper](http://www.hogbaysoftware.com), and creates a url which:
4 | - Links back to the current document,
5 | - restores the current selection, and:
6 | - also restores any filters that are currently applied to the document.
7 |
8 | For example, the following link, which has various optional switches
9 |
10 | `tp3doc:///Users/houthakker/Library/Application%20Support/Notational%20Velocity/notes-2014-06-30.txt?nodepath=///@priority?selnpath=/heil/a%20se/why/who/inte?find=Intermediaries?line=10?startoffset=5?endoffset=19`
11 |
12 | 1. Reopens a particular document in a Notational Velocity text file folder,
13 | 2. restores the `//@priority` filter path from the `?nodepath=` switch
14 | 3. attempts to restore the selection by looking for a node which matches the `?selnpath=` nodepath
15 | 4. if it finds nothing matched by the `?selnpath=` switch, selects the first node with text matching the `?find=` switch
16 | 4. and if all else fails selects whatever is specified by the optional `?line=`, `?startoffset` and `?endoffset=` switches
17 |
18 | Note that the file path and any other text or node paths are automatically uri-encoded by the script.
19 |
20 | ### Use
21 | - Select a line or phrase in TaskPaper
22 | - Run [TP3CopyAsURL](./TP3CopyAsURL.applescript)
23 | - Paste the resulting tp3doc:// url wherever you need it.
24 | - (It can be used for example, to provide active links between or within TaskPaper documents)
25 |
26 | #### tp3doc:// url-scheme for opening a TaskPaper document at a specific line
27 | The tp3doc:// url-scheme is registered and handled by an Applescript, [OpenTP3docAtLine](./OpenTP3docAtLine.app):
28 |
29 | ###### OpenTP3docAtLine.app
30 | - Is an [applescript](https://github.com/RobTrew/txtquery-tools/blob/master/tp3doc%20url%20scheme%20and%20TP3CopyAsURL/Source%20and%20info.plist%20for%20OpenTP3DocAtLine/OpenTP3DocAtLine.applescript) saved as an .app bundle
31 | - contains an [Info.plist](https://github.com/RobTrew/txtquery-tools/blob/master/tp3doc%20url%20scheme%20and%20TP3CopyAsURL/Source%20and%20info.plist%20for%20OpenTP3DocAtLine/Info.plist) which registers `tp3doc://`
32 | - contains an open url handler which:
33 | - Opens a specified text document in [TaskPaper](http://www.hogbaysoftware.com)
34 | - applies any filter given in a `?nodepath=`
35 | - selects any line specified in a `?line=` switch
36 | (if the line is hidden by the nodepath filter, the editor unfolds just enough to make the line visible)
37 | - optionally restricts the selection to a part of the line, using any character position specified by either or both of the following switches
38 | - `?startoffset=`
39 | - `?endoffset=`
40 |
41 | NB if you want to create _tp3doc://_ urls ‘by hand’ or with a script of your own, you will need to uri-encode the file path and any nodepath. There are various ways of doing this at the command line, or in an applescript, with something like:
42 |
43 | ```
44 | on encode(strPath)
45 | do shell script "python -c 'import sys, urllib as ul; print ul.quote(sys.argv[1])' " & quoted form of strPath
46 | end encode
47 | ```
48 |
49 | Easier, of course, in Javascript: `encodeURI()` for a whole link, or `encodeURIComponent()` for parts excluding the opening scheme name.
50 |
51 |
52 | #### Installation
53 |
54 | For the _tp3doc://_ url scheme to be registered, [OpenTP3docAtLine](./OpenTP3docAtLine.app) needs to be on your system, and needs to have been run at least once.
55 | To do this:
56 | - EITHER extract the copy from the [txtquery-tools](https://github.com/RobTrew/txtquery-tools) repository [zip file](https://github.com/RobTrew/txtquery-tools/archive/master.zip), and ctrl-click to allow the OS X Gate Keeper security system to run it
57 | - OR:
58 | - open the .applescript text version Applescript editor,
59 | - save as an .app bundle
60 | - Ctrl-click on the .app bundle to _Open Package Contents_
61 | - and replace the info.plist file with the version which declares the url-scheme
62 |
63 | [Repository .zip file](https://github.com/RobTrew/txtquery-tools/archive/master.zip)
64 |
65 | ##### Reference
66 | For an explanation of this approach to registering and handling a url with an applescript.app, and the info.plist in its bundle,
67 | See [http://www.macosxautomation.com/applescript/linktrigger/](http://www.macosxautomation.com/applescript/linktrigger/)
68 |
69 | (Many thanks to Jamie Kowalski for drawing my attention to this approach, which he uses in his excellent [wikilink plugin](https://github.com/jamiekowalski/TaskPaper-extra/blob/master/wikilink.ftplugin/README.md) for TaskPaper)
70 |
71 |
72 |
--------------------------------------------------------------------------------
/relative dates and date adjustments.ftplugin/TaskPaper.textexpander:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | groupInfo
6 |
7 | expandAfterMode
8 | 1
9 | groupName
10 | TaskPaper
11 |
12 | snippetsTE2
13 |
14 |
15 | abbreviation
16 |
17 | abbreviationMode
18 | 0
19 | creationDate
20 | 2014-04-24T21:25:07Z
21 | flags
22 | 0
23 | label
24 |
25 | modificationDate
26 | 2014-04-24T21:30:40Z
27 | plainText
28 | INSTALLATION
29 | These snippets require installation of the plugin at:
30 | https://github.com/RobTrew/tree-tools/tree/master/FoldingText%202%20plugins%20and%20scripts
31 |
32 | In FoldingText:
33 | 1. File > Open Application Folder
34 | 2. Copy the relative dates.ftplugin folder into the Plugins folder
35 | 3. Restart FoldingText
36 | snippetType
37 | 0
38 | useCount
39 | 0
40 | uuidString
41 | 6CCCC4BB-0F28-4953-92CA-B9C872699CA8
42 |
43 |
44 | abbreviation
45 | @st
46 | abbreviationMode
47 | 0
48 | creationDate
49 | 2012-11-24T23:03:24Z
50 | flags
51 | 0
52 | label
53 |
54 | lastUsed
55 | 2014-04-24T21:24:18Z
56 | modificationDate
57 | 2014-04-24T21:20:46Z
58 | plainText
59 | @start(%snippet:smt%%|)
60 | snippetType
61 | 0
62 | useCount
63 | 45
64 | uuidString
65 | 8ED78F8D-2065-49F4-A9A4-5775486B9E8C
66 |
67 |
68 | abbreviation
69 | @du
70 | abbreviationMode
71 | 0
72 | creationDate
73 | 2012-11-24T23:03:24Z
74 | flags
75 | 0
76 | label
77 |
78 | lastUsed
79 | 2014-04-24T21:22:54Z
80 | modificationDate
81 | 2014-04-24T20:53:11Z
82 | plainText
83 | @due(%snippet:smt%%|)
84 | snippetType
85 | 0
86 | useCount
87 | 45
88 | uuidString
89 | 8825976A-C013-447A-A498-36B2C6237F8B
90 |
91 |
92 | abbreviation
93 | smt
94 | abbreviationMode
95 | 0
96 | creationDate
97 | 2012-11-24T21:52:58Z
98 | flags
99 | 1
100 | label
101 | Convert date time or adjustment to ISO
102 | lastUsed
103 | 2012-11-25T12:26:42Z
104 | modificationDate
105 | 2014-04-24T21:32:44Z
106 | plainText
107 | property pName : "smalltime"
property pDescription : "'open date phrase panel'"
property pVer : "0.1"
property pPluginLink : "https://github.com/RobTrew/tree-tools/tree/master/FoldingText%202%20plugins%20and%20scripts"
tell application "TaskPaper"
set lstDocs to documents
if lstDocs ≠ {} then
activate
tell item 1 of lstDocs
set varResult to (evaluate script "function(editor, options) {
108 | return editor.performCommand(options.command);
109 | }" with options {command:pName})
end tell
if varResult = false then
set strBtnLink to "Go to Plugin page"
tell (display dialog "Plugin not installed:" & linefeed & linefeed & pName & " – " & pDescription & linefeed & linefeed & pPluginLink buttons {strBtnLink, "OK"} default button "OK" with title pName & " ver. " & pVer)
if button returned = strBtnLink then ¬
tell me to do shell script "open " & quoted form of pPluginLink
end tell
end if
end if
end tell
110 | snippetType
111 | 2
112 | useCount
113 | 11
114 | uuidString
115 | 1B2445AD-8BF5-47A6-BCA5-4B123720D937
116 |
117 |
118 |
119 |
120 |
--------------------------------------------------------------------------------
/relative dates and date adjustments.ftplugin/FoldingTextOLD.textexpander:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | groupInfo
6 |
7 | expandAfterMode
8 | 1
9 | groupName
10 | FoldingText
11 |
12 | snippetsTE2
13 |
14 |
15 | abbreviation
16 |
17 | abbreviationMode
18 | 0
19 | creationDate
20 | 2014-04-24T21:25:07Z
21 | flags
22 | 0
23 | label
24 |
25 | modificationDate
26 | 2014-04-24T21:30:40Z
27 | plainText
28 | INSTALLATION
29 | These snippets require installation of the plugin at:
30 | https://github.com/RobTrew/tree-tools/tree/master/FoldingText%202%20plugins%20and%20scripts
31 |
32 | In FoldingText:
33 | 1. File > Open Application Folder
34 | 2. Copy the relative dates.ftplugin folder into the Plugins folder
35 | 3. Restart FoldingText
36 | snippetType
37 | 0
38 | useCount
39 | 0
40 | uuidString
41 | DD26392B-534A-41FE-9933-4A05D5BA513D
42 |
43 |
44 | abbreviation
45 | @st
46 | abbreviationMode
47 | 0
48 | creationDate
49 | 2012-11-24T23:03:24Z
50 | flags
51 | 0
52 | label
53 |
54 | lastUsed
55 | 2014-04-24T21:24:18Z
56 | modificationDate
57 | 2014-04-24T21:20:46Z
58 | plainText
59 | @start(%snippet:smt%%|)
60 | snippetType
61 | 0
62 | useCount
63 | 45
64 | uuidString
65 | 00B9035B-DE9F-464C-84C5-DD4A63797369
66 |
67 |
68 | abbreviation
69 | @du
70 | abbreviationMode
71 | 0
72 | creationDate
73 | 2012-11-24T23:03:24Z
74 | flags
75 | 0
76 | label
77 |
78 | lastUsed
79 | 2014-04-24T21:22:54Z
80 | modificationDate
81 | 2014-04-24T20:53:11Z
82 | plainText
83 | @due(%snippet:smt%%|)
84 | snippetType
85 | 0
86 | useCount
87 | 45
88 | uuidString
89 | DCD61060-751F-4436-B9F5-322B0EB5B166
90 |
91 |
92 | abbreviation
93 | smt
94 | abbreviationMode
95 | 0
96 | creationDate
97 | 2012-11-24T21:52:58Z
98 | flags
99 | 1
100 | label
101 | Convert date time or adjustment to ISO
102 | lastUsed
103 | 2012-11-25T12:26:42Z
104 | modificationDate
105 | 2014-04-24T20:49:26Z
106 | plainText
107 | property pName : "smalltime"
property pDescription : "'open date phrase panel'"
property pVer : "0.1"
property pPluginLink : "https://github.com/RobTrew/tree-tools/tree/master/FoldingText%202%20plugins%20and%20scripts"
tell application "FoldingText"
set lstDocs to documents
if lstDocs ≠ {} then
activate
tell item 1 of lstDocs
set varResult to (evaluate script "function(editor, options) {
108 | return editor.performCommand(options.command);
109 | }" with options {command:pName})
end tell
if varResult = false then
set strBtnLink to "Go to Plugin page"
tell (display dialog "Plugin not installed:" & linefeed & linefeed & pName & " – " & pDescription & linefeed & linefeed & pPluginLink buttons {strBtnLink, "OK"} default button "OK" with title pName & " ver. " & pVer)
if button returned = strBtnLink then ¬
tell me to do shell script "open " & quoted form of pPluginLink
end tell
end if
end if
end tell
110 | snippetType
111 | 2
112 | useCount
113 | 11
114 | uuidString
115 | 3C54AA1B-1647-48C8-BD74-F062E590969C
116 |
117 |
118 |
119 |
120 |
--------------------------------------------------------------------------------
/links between plain text and Reminders/README.md:
--------------------------------------------------------------------------------
1 |
2 | ### Plain text project files with links to and from Reminders.app
3 | Nothing beats plain text outlines for quickly and flexibly gathering thoughts and developing project structure, and well synched databases like Reminders.app are very good for automating alerts.
4 |
5 | Plain text and Reminders can be linked to each other, and we can script the creation of these links (and the exchange of dates and other details between our notes and our reminders).
6 |
7 | #### Creating links back and forth between plain text and reminders,
8 |
9 | ##### Plain text links to alerts in Reminders.app
10 |
11 | 
12 |
13 | These links are made possible by the [x-apple-reminder://](x-apple-reminder://) URL scheme of Reminders.app
14 |
15 | *FoldingText > View > Show Syntax*
16 |
17 | 
18 |
19 | We can create these links automatically, either copying them from existing Reminders,
20 |
21 | 
22 |
23 | as TaskPaper / FoldingText entries, [with this script,](./CopyReminderAsTaskPaperOrFT.applescript)
24 |
25 | 
26 |
27 | (result with MD link and TaskPaper-style tags)
28 |
29 | - Release a raven and a dove after 40 days [🕖](x-apple-reminder://144D021C-06D7-4FE0-AE28-76295FDCB08C) @list(voyage) @alert(2015-03-29 07:00) @priority(2)
30 |
31 |
32 | OR simply as MD links, [with another script.](./CopyReminderAsLink.applescript)
33 |
34 | 
35 |
36 | (Resulting link to a reminder):
37 |
38 | [🕖](x-apple-reminder://144D021C-06D7-4FE0-AE28-76295FDCB08C)
39 |
40 | Alternatively, we can automatically push details from plain text entries to create new reminders
41 |
42 | 1. Select a line which contains an `@alert(date/time) tag (the date/time can be informal or relative) ...
43 | 
44 |
45 | 2. Run the script [FTMakeOrUpdateReminder.scpt](./FTMakeOrUpdateReminder.applescript) in Applescript Editor
46 | 
47 |
48 | A clock-faced link to a new reminder is created:
49 | 
50 |
51 | and the note of the new reminder also contains a link **back** to the FoldingText entry:
52 | 
53 |
54 | ##### Links from Reminders.app back to plain text
55 | - There are url schemes for linking to particular lines TaskPaper and Foldingtext files,
56 | - [ftdoc://](https://github.com/RobTrew/txtquery-tools/blob/master/ftdoc%20url%20scheme%20and%20FTCopyAsURL/README.md)
57 | - [tp3doc://](https://github.com/RobTrew/txtquery-tools/blob/master/tp3doc%20url%20scheme%20and%20TP3CopyAsURL/README.md)
58 | - To download and install these url schemes, see:
59 | - [FoldingText 2 url scheme ftdoc://](https://github.com/RobTrew/txtquery-tools/blob/master/ftdoc%20url%20scheme%20and%20FTCopyAsURL/README.md)
60 | - [TaskPaper 3 url scheme tp3doc://](https://github.com/RobTrew/txtquery-tools/blob/master/tp3doc%20url%20scheme%20and%20TP3CopyAsURL/README.md)
61 |
62 | #### Synching adjusted details
63 |
64 | The values of various `@key(value` tags in plain text notes,
65 |
66 | - `@alert(yyyy-mm-dd HH:MM)`
67 | - `@priority(1|2|3)`
68 | - `@done(yyyy-mm-dd HH:MM)`
69 | - `@cal(list name)`
70 |
71 | can be sent back and forth by script between text and Reminders.app.
72 |
73 | - [Pushing details from FoldingText to Reminders](./FTMakeOrUpdateReminder.applescript)
74 | - [Pulling details from Reminders to FoldingText](./FTPullDetailsFROMLinkedReminder.applescript)
75 | - [Toggling @done status at both ends](./FTToggleDoneUpdateReminders.applescript)
76 |
77 | 1. Make some edits in FoldingText to the value(s) of any @alert or @priority tag(s)
78 | 
79 |
80 | (any new dates or times can be relative or informal)
81 |
82 | 2. then run the create/update script again.
83 |
84 | The clock-face icon and time display will be normalized in FT:
85 | 
86 |
87 | and the linked reminder will be updated to the new time and priority level:
88 | 
89 |
90 |
91 | #### Using relative date / time expressions
92 | The update script understands the same set of relative and informal date time expressions as the [Relative dates and date adjustment](../relative%20dates%20and%20date%20adjustments.ftplugin/README.md) plugin for FoldingText.
93 |
94 |
95 | #### Installation
96 | The applescripts require installation of [smalltime.ftplugin](../smalltime.ftplugin) and [reminder tools.ftplugin](../reminder%20tools.ftplugin) plugins for FoldingText.
97 |
98 | - [txtQuery Tools repository](https://github.com/RobTrew/txtquery-tools)
99 | - [Download .zip](https://github.com/RobTrew/txtquery-tools/archive/master.zip)
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
--------------------------------------------------------------------------------
/ftdoc url scheme and FTCopyAsURL/README.md:
--------------------------------------------------------------------------------
1 | ### Copy FoldingText selection as ftdoc:// link back to document, line, selection and filter state
2 |
3 | The [FTCopyAsURL](./FTCopyAsURL.applescript) applescript copies the currently selected text position in [FoldingText](http://www.foldingtext.com), and creates a url which:
4 | - Links back to the current document,
5 | - restores the current selection, and:
6 | - also restores any filters that are currently applied to the document.
7 |
8 | For example, the following link, which has various optional switches
9 |
10 | `ftdoc:///Users/robintrew/Library/Application%20Support/Notational%20Velocity/notes-2014-06-30.txt?nodepath=///@priority?selnpath=/heil/a%20se/why/who/inte?find=Intermediaries?line=10?startoffset=5?endoffset=19`
11 |
12 | 1. Reopens a particular document in a Notational Velocity text file folder,
13 | 2. restores the `//@priority` filter path from the `?nodepath=` switch
14 | 3. attempts to restore the selection by looking for a node which matches the `?selnpath=` nodepath
15 | 4. if it finds nothing matched by the `?selnpath=` switch, selects the first node with text matching the `?find=` switch
16 | 4. and if all else fails selects whatever is specified by the optional `?line=`, `?startoffset` and `?endoffset=` switches
17 |
18 | Note that the file path and any other text or node paths are automatically uri-encoded by the script.
19 |
20 | ### Applications
21 | - As a kind of bookmark to a particular point in a document
22 | - As a way (when using the [FoldingText CLI](https://www.npmjs.org/package/foldingtext) to generate a single perspective or report from several documents) of creating links which jump back from the perspective to a specific document and line.
23 |
24 | ### Use
25 | - Select a line or phrase in FoldingText
26 | - Run [FTCopyAsURL](./FTCopyAsURL.applescript)
27 | - Paste the resulting ftdoc:// url wherever you need it.
28 | - (It can be used for example, to provide active links between or within FoldingText documents)
29 |
30 | #### ftdoc:// url-scheme for opening a FoldingText document at a specific line
31 | The ftdoc:// url-scheme is registered and handled by an Applescript, [OpenFTDocAtLine](./OpenFTDocAtLine.app):
32 |
33 | ###### OpenFTDocAtLine.app
34 | - Is an [applescript](https://github.com/RobTrew/txtquery-tools/blob/master/ftdoc%20url%20scheme%20and%20FTCopyAsURL/Source%20and%20info.plist%20for%20OpenFTDocAtLine/OpenFTDocAtLine.applescript) saved as an .app bundle
35 | - contains an [Info.plist](https://github.com/RobTrew/txtquery-tools/blob/master/ftdoc%20url%20scheme%20and%20FTCopyAsURL/Source%20and%20info.plist%20for%20OpenFTDocAtLine/Info.plist) which registers `ftdoc://`
36 | - contains an open url handler which:
37 | - Opens a specified text document in [FoldingText](http://www.foldingtext.com)
38 | - applies any filter given in a `?nodepath=`
39 | - selects any line specified in a `?line=` switch
40 | (if the line is hidden by the nodepath filter, the editor unfolds just enough to make the line visible)
41 | - optionally restricts the selection to a part of the line, using any character position specified by either or both of the following switches
42 | - `?startoffset=`
43 | - `?endoffset=`
44 |
45 | NB if you want to create _ftdoc://_ urls ‘by hand’ or with a script of your own, you will need to uri-encode the file path and any nodepath. There are various ways of doing this at the command line, or in an applescript, with something like:
46 |
47 | ```
48 | on encode(strPath)
49 | do shell script "python -c 'import sys, urllib as ul; print ul.quote(sys.argv[1])' " & quoted form of strPath
50 | end encode
51 | ```
52 |
53 | Easier, of course, in Javascript: `encodeURI()` for a whole link, or `encodeURIComponent()` for parts excluding the opening scheme name.
54 |
55 |
56 | #### Installation
57 |
58 | For the _ftdoc://_ url scheme to be registered, [OpenFTDocAtLine](./OpenFTDocAtLine.app) needs to be on your system, and needs to have been run at least once.
59 | To do this:
60 | - EITHER extract the copy from the [txtquery-tools](https://github.com/RobTrew/txtquery-tools) repository [zip file](https://github.com/RobTrew/txtquery-tools/archive/master.zip), and ctrl-click to allow the OS X Gate Keeper security system to run it
61 | - OR:
62 | - open the .applescript text version Applescript editor,
63 | - save as an .app bundle
64 | - Ctrl-click on the .app bundle to _Open Package Contents_
65 | - and replace the info.plist file with the version which declares the url-scheme
66 |
67 | [Repository .zip file](https://github.com/RobTrew/txtquery-tools/archive/master.zip)
68 |
69 | ##### Reference
70 | For an explanation of this approach to registering and handling a url with an applescript.app, and the info.plist in its bundle,
71 | See [http://www.macosxautomation.com/applescript/linktrigger/](http://www.macosxautomation.com/applescript/linktrigger/)
72 |
73 | (Many thanks to Jamie Kowalski for drawing my attention to this approach, which he uses in his excellent [wikilink plugin](https://github.com/jamiekowalski/foldingtext-extra/blob/master/wikilink.ftplugin/README.md) for FoldingText)
74 |
75 |
76 |
--------------------------------------------------------------------------------
/reminder tools.ftplugin/main.js:
--------------------------------------------------------------------------------
1 | // Interpret date tags:
2 | // 1. Informal or relative phrases in
3 | // specified date tags in selected line are converted to ISO
4 | // 2. The date and other values are returned to any calling Applescript
5 | // through window.RTpluginReturn, so that a linked Reminder.app
6 | // can be updated or created.
7 |
8 | define(function(require, exports, module) {
9 | 'use strict';
10 |
11 | var Extensions = require('ft/core/extensions').Extensions,
12 | dateLogic = require('../smalltime.ftplugin/main.js'),
13 | Editor;
14 |
15 | function updateAndReadForLink(Editor, dctArgs) {
16 |
17 | var lstResults = translateDateTags(Editor, dctArgs),
18 | node = lstResults[0], strLine = node.line(),
19 | strText = node.text(), strLabel=dctArgs['linklabel'],
20 | dctReturn = lstResults[1], strTag='', oMatch, dteAlarm,
21 | lstHeat = dctArgs.heat || [], lngHeat = 0, i,
22 | rgxReminder = /\[[^\]]*\]\((x-apple-reminder:\/\/[A-F0-9]{8}-[A-F0-9]{4}-[A-F0-9]{4}-[A-F0-9]{4}-[A-F0-9]{12})\)/;
23 |
24 | // Find the highest priority/heat tag and return a 1-based index
25 | lngHeat = lstHeat.length;
26 | for (i=0; i 2) i=2;
31 | dctReturn.heat = i+1;
32 | break;
33 | }
34 | }
35 |
36 | // Separate any Reminders UUID from the main text entry
37 | oMatch = rgxReminder.exec(strText);
38 | if (oMatch) {
39 | dctReturn.uuid = oMatch[1];
40 | dctReturn.text = strText.substring(0, oMatch.index-1);
41 | } else dctReturn.text = strText;
42 |
43 | //translate any linklabel
44 | if (strLabel) {
45 | dteAlarm=dctReturn['alarmtime'];
46 | if (dteAlarm) strLabel=dateLogic.timeEmoji(strLabel, dteAlarm);
47 | else strLabel=dateLogic.timeEmoji(strLabel);
48 | } else strLabel='??';
49 | dctReturn['linklabel']=strLabel;
50 |
51 | // return the harvest for any calling Applescript
52 |
53 | return dctReturn;
54 | }
55 |
56 | // translate values of specified date tags to ISO (if informal/relative)
57 | // and return any values for uuid, text, alarm tag, priority,
58 | // and any other requested date tags
59 | function translateDateTags(Editor, dctArgs) {
60 | var lstUpdateTags = ['alarm'],
61 | tree = Editor.tree(),
62 | node = Editor.selectedRange().startNode,
63 | dctReturn = {'uuid':null, 'text':null, 'alarm':null,
64 | 'alarmlist':null,'datetext':null, 'iso':null, 'heat':null},
65 | dctNodeTags = node.tags(),
66 | lstNodeTags = Object.keys(dctNodeTags), strKey='', strVal,
67 | lngSeconds=0, lstKeySet, lngTag,
68 | strTrans='', dteUpdated, strAlarmKey, blnDelta, i;
69 |
70 | // read any arguments to override defaults for alarm,
71 | // other date tags, and priority tags
72 | if (typeof dctArgs !== 'undefined') {
73 | strAlarmKey = dctArgs.alarm || 'alarm';
74 | if (strAlarmKey.charAt(0) === '@')
75 | strAlarmKey = strAlarmKey.substring(1);
76 | lstUpdateTags = dctArgs.others || [];
77 | lstUpdateTags.push(strAlarmKey);
78 | }
79 | // strip any leading '@' from date tags to get the key
80 | lngTag = lstUpdateTags.length;
81 | for (i=0; i irngEnd));
55 | }
56 |
57 | // return the selected text
58 | // or select and return the value of any @key(value) tag at the cursor
59 | function selectDate() {
60 | // is the cursor in or next to a tag ?
61 | var rngSeln = Editor.selectedRange(), node = rngSeln.startNode,
62 | lngLineStart = node.lineTextStart(),
63 | oTree = Editor.tree(),
64 | iSelnFrom = rngSeln.location() - lngLineStart,
65 | iSelnTo = iSelnFrom + rngSeln.length(),
66 | iTagFrom = 0, iTagTo = 0, iValFrom=0,
67 | strLine = node.line(),
68 | nodeTags = node.tags(), strKey, strVal, lngChars=0,
69 | lstTag=[], lngKeyChars, lngValChars, strText;
70 |
71 | // look for any tag at the cursor
72 | if (nodeTags) {
73 | Object.keys(nodeTags).forEach(function(strKey) {
74 | strVal = node.tag(strKey);
75 | lngKeyChars = strKey.length;
76 | if (strVal) {
77 | lngValChars = strVal.length;
78 | lngChars = lngKeyChars + lngValChars + 3;
79 | lngKeyChars +=2;
80 | } else {
81 | lngChars = lngKeyChars + 1;
82 | lngValChars = 0;
83 | lngKeyChars +=1;
84 | }
85 | iTagFrom = strLine.indexOf('@' + strKey);
86 | iTagTo = iTagFrom + lngChars;
87 |
88 | // is the cursor in or touching a tag ?
89 | if (overLapsWith(iSelnFrom, iSelnTo,
90 | iTagFrom, iTagTo)) {
91 | lstTag.push([iTagFrom + lngKeyChars,
92 | lngValChars]);
93 | }
94 | });
95 | if (lstTag.length) { // cursor in/touching tag
96 | iValFrom = lngLineStart + lstTag[0][0];
97 | lngValChars = lstTag[0][1];
98 | //tag selected but no value
99 | //place cursor between pair of new brackets
100 | if (!lngValChars) {
101 | rngSeln = oTree.createRangeFromLocation(
102 | iValFrom, 0);
103 | Editor.replaceSelection('()');
104 | iValFrom +=1;
105 | }
106 | rngSeln = oTree.createRangeFromLocation(
107 | iValFrom, lngValChars);
108 | Editor.setSelectedRange(rngSeln);
109 | }
110 | }
111 |
112 | strText = Editor.selectedText();
113 | return strText;
114 | }
115 |
116 | Extensions.add('com.foldingtext.editor.commands', {
117 | name: 'informal dates and adjustments',
118 | description: 'open date phrase panel',
119 | performCommand: show_date_panel
120 | });
121 |
122 | Extensions.add('com.foldingtext.editor.init', function(editor) {
123 | Editor = editor;
124 |
125 | panel = new Panel({
126 | className: 'RTDatePanel',
127 | placeholder: 'enter date phrase ...',
128 | onReturn: function() {
129 | panel.clear();
130 | Editor.performCommand('moveRight');
131 | Editor.performCommand('moveRight');
132 | },
133 | onBlur: function() {
134 | panel.clear();
135 | },
136 | onTextChange: function() {
137 | translatePhrase(panel.input.value);
138 | }
139 | });
140 |
141 | Editor.addKeyMap({
142 | "Cmd-Alt-'" : 'informal dates and adjustments'
143 | //Shift-, Cmd-, Ctrl-, and Alt- (in that order!) to
144 | });
145 | Editor.addKeyMap({
146 | //open bracket with Cmd held down
147 | "Shift-Cmd-9" : 'informal dates and adjustments'
148 | });
149 | });
150 |
151 |
152 |
153 | });
154 |
--------------------------------------------------------------------------------
/structure editing/MoveSelnToSectionJS.applescript:
--------------------------------------------------------------------------------
1 | // Yosemite JavaScript for Applications (JXA) version
2 | function run() {
3 |
4 | var dctScript = {
5 | title: "Move line(s) to new section",
6 | version: "0.04",
7 | author: "RobTrew",
8 | license: "MIT: ALL copies should include the license notice at https://github.com/RobTrew/txtquery-tools"
9 | }
10 |
11 | var blnDebug = 0; // zero unless using the symbolic debugger
12 |
13 |
14 | // JSLR
15 | // edit to `blnTPIndent = true` for an extra TaskPaper indent - false for default formatting
16 | var blnTPIndent = false;
17 |
18 |
19 | var docsFT = Application("FoldingText").documents(),
20 | oDoc = docsFT.length ? docsFT[0] : null;
21 |
22 | if (!oDoc) return null;
23 |
24 |
25 | // GET LIST OF HEADING TITLES AND THEIR MINIMUM PATHS (+ any selected text)
26 | var fnProcess = (blnDebug ? oDoc.debug : oDoc.evaluate),
27 | lstHeadsAndSeln = fnProcess({
28 | script: sectionList.toString()
29 | }),
30 | lstMenu = lstHeadsAndSeln[0],
31 |
32 | lstSectionPaths = lstHeadsAndSeln[1],
33 | strSeln = lstHeadsAndSeln[2],
34 | lstNumberedMenu = numberedMenu(lstMenu);
35 |
36 | // Exit here, if the document contains no headers
37 | if (!lstNumberedMenu.length) return 0;
38 |
39 | // GET USER CHOICE
40 | var app = Application.currentApplication(),
41 | mbChoice, varResult;
42 |
43 | app.includeStandardAdditions = true;
44 |
45 | mbChoice = maybeChoiceIndex(
46 | app.chooseFromList(lstNumberedMenu, {
47 | withTitle: dctScript.title,
48 | withPrompt: "Choose new section for selected line(s):\n\n" + strSeln +
49 | "\n",
50 | defaultItems: lstNumberedMenu[0],
51 | okButtonName: "Move",
52 | cancelButtonName: "Cancel",
53 | multipleSelectionsAllowed: false,
54 | emptySelectionAllowed: false,
55 | })
56 | );
57 |
58 |
59 | // IF A TARGET SECTION HAS BEEN CHOSEN, MOVE THE SELECTION
60 | if (mbChoice) {
61 | return fnProcess({
62 | script: itemMove.toString(),
63 | withOptions: {
64 | // JSLR
65 | taskpaperindent: blnTPIndent,
66 | targetpath: lstSectionPaths[mbChoice]
67 | }
68 | });
69 | } else return null;
70 | }
71 |
72 | // Number of any target section chosen, or null if no choice
73 | function maybeChoiceIndex(varResult) {
74 | return varResult ?
75 | parseInt(varResult[0].split('\t')[0]) : null;
76 | }
77 |
78 | // move selected item(s) to target path
79 | function itemMove(editor, options) {
80 |
81 | // FIND THE TARGET SECTION
82 | var oTree = editor.tree(),
83 | oNewParent = oTree.evaluateNodePath(options.targetpath + '[0]')[0],
84 | rngSeln = editor.selectedRange(),
85 | lstNodes = rngSeln.nodesInRange(),
86 | lstSeen = [],
87 | lstSelnRoots = [],
88 | strID,
89 |
90 | // edit (1 of 2) for JSLR (using TaskPaper format in FT)
91 | blnExtraIndent = options.taskpaperindent;
92 |
93 | // WORK ONLY WITH THE HIGHEST LEVEL NODES IN THE SELECTION
94 | // (CHILDREN TRAVEL WITH THEM)
95 | lstNodes.forEach(function (oNode) {
96 | strID = oNode.parent.id;
97 | if (lstSeen.indexOf(strID) == -1) {
98 | lstSelnRoots.push(oNode);
99 | lstSeen.push(oNode.id);
100 | }
101 | });
102 |
103 | // APPEND EACH SELECTED PARENT NODE TO THE CHOSEN TARGET NODE
104 | // Taking children with each parent, unless we are relocating an ancestor under one
105 | // of its own descendants (demoted ancestors travel alone)
106 |
107 | lstSelnRoots.forEach(function (oNode) {
108 | if (oNewParent.isAncestorOfSelf(oNode)) //detach traveller from its descendants before moving it
109 | oTree.removeNode(oNode);
110 |
111 | oNewParent.appendChild(oNode); // by default children travel with parents
112 |
113 | // edit (2 of 2) for JSLR (using TaskPaper format in FT)
114 | if (blnExtraIndent)
115 | oNode.setLine('\t' + oNode.line())
116 | });
117 | }
118 |
119 | // GATHER LIST OF SECTIONS FOR THE UI MENU
120 | function sectionList(editor) {
121 | var libNodePath = require('ft/core/nodepath').NodePath,
122 | oTree = editor.tree(),
123 | lstHeads = oTree.evaluateNodePath('//@type=heading'),
124 | lstSelnNodes = editor.selectedRange().nodesInRange(),
125 | lngSeln = lstSelnNodes.length;
126 |
127 | var lstMenu = [],
128 | lstPath = [],
129 | strText = '',
130 | rngLines;
131 |
132 |
133 | // get any selected text
134 | if (lngSeln) {
135 | rngLines = oTree.createRangeFromNodes(lstSelnNodes[0], 0, lstSelnNodes[
136 | lngSeln - 1], -1);
137 | strText = rngLines.textInRange().trim();
138 | }
139 |
140 |
141 | // and get each heading, plus its full outline path (compressed)
142 | lstHeads.forEach(function (oHead) {
143 | // header title
144 | lstMenu.push(
145 | [Array(oHead.typeIndentLevel() + 1).join('#'),
146 | oHead.text()
147 | ].join(' ')
148 | );
149 | // and compressed header path
150 | lstPath.push(libNodePath.calculateMinNodePath(oHead));
151 | });
152 |
153 |
154 | // headers, their outline paths, and any selected text
155 | return [lstMenu, lstPath, strText];
156 | }
157 |
158 |
159 | // List of strings re written with zero-padded numeric prefixes
160 | // [strItem] ? maybeStringSeparator ? [strNumberedItem]
161 | function numberedMenu(lstItems, strSeparator) {
162 | // default separator between number string and item string
163 | strSeparator = strSeparator || '\t';
164 |
165 | var lng = lstItems.length,
166 | lngPadWidth = lng.toString().length;
167 |
168 | // Numbers string padded to left with zeros to get fixed width
169 | // intNumber --> intDigits --> strDigits
170 | function zeroPad(intNumber, intDigits) {
171 | var strUnpadded = intNumber.toString(),
172 | intUnpadded = strUnpadded.length;
173 |
174 | return Array((intDigits - intUnpadded) + 1).join('0') + strUnpadded;
175 | }
176 |
177 | // list rewritten with numeric prefixes of even length
178 | // left-padded with zeros where needed
179 | return lstItems.map(function (str, i) {
180 | return zeroPad(i, lngPadWidth) + strSeparator + str;
181 | });
182 | }
--------------------------------------------------------------------------------
/ftdoc url scheme and FTCopyAsURL/Source and info.plist for OpenFTDocAtLine/OpenFTDocAtLine.applescript:
--------------------------------------------------------------------------------
1 | property pTitle : "Register and handle ftdoc:// url scheme"
property pVer : "0.04"
property pAuthor : "Rob Trew"
property pDescription : "
2 |
3 | Use in conjunction with the 'FTCopyAsURL' Applescript to get
4 | a URL which opens the specified document, optionally restoring selection and filter state.
5 |
6 | "
-- Registers the url-scheme ftdoc://encoded-file-path with optional switches:
--[?nodepath=//@due] -- nodepath used to apply a filter
--[?selnpath=] -- nodepath used to specify a selection
--[?find=] -- text string to find
--[?line=N][?startoffset=0][?endoffset=-1]
-- where line is zero-based and defaults to 0
-- startoffset is an offset of a number of characters from the start of the line
-- endoffset is ditto
-- and the url opens the document in FoldingText:
-- 1. Applying any specified ?nodepath= value as a filter
-- 2. Selecting the first line that matches (in the following order)
-- -- the value of ?selnpath= ?find= or ?line=
-- 3. Restricts the selection to a subset of a line selected by number if startoffset > 0 or endoffset ≠ -1
-- for the approach to registering and handling a url with an applescript.app and the .plist in its bundle,
-- see http://www.macosxautomation.com/applescript/linktrigger/
property piNodePath : 1
property piSelnPath : 2
property piFindText : 3
property piLine : 4
property piStartOffset : 5
property piEndOffset : 6
property plstKeys : {"nodepath", "selnpath", "find", "line", "startoffset", "endoffset"}
property plngKeys : length of plstKeys
property pjsSelect : "
7 |
8 | function(editor, options) {
9 | function getValue(strSwitch) {
10 | return lstSwitches[lstSwitches.indexOf('?' + strSwitch + '=')+1];
11 | }
12 |
13 | var tree= editor.tree(),
14 | oNode, rngSeln,
15 | //options.filepath, options.switches, options.keys
16 | lstKeys = options.keys,
17 | strRegex = '(\\\\?' + lstKeys.join('=|\\\\?') + '=)',
18 | oRegex = new RegExp(strRegex, 'g'),
19 | strPath = decodeURIComponent(options.filepath),
20 | strSwitches = decodeURIComponent(options.switches),
21 | lstSwitches = strSwitches.split(oRegex),
22 | strPath, strLineNum,
23 | strSelnPath,
24 | strFind,
25 | strStartOffset, strEndOffset,
26 | lngLine, lngStartOffset=0, lngEndOffset=-1,
27 | varStartOffset, varEndOffset,
28 | lstMatches=[], lstRanges=[], i;
29 |
30 |
31 | // Try to restore any selection that is specified
32 | if (strPath = getValue('nodepath')) {
33 | //restore any filter
34 | editor.setNodePath(strPath);
35 | }
36 |
37 |
38 | strSelnPath = getValue('selnpath');
39 | strFind = getValue('find');
40 |
41 | if (strSelnPath || strFind) {
42 | if (strSelnPath) {
43 | lstMatches = tree.evaluateNodePath(strSelnPath);
44 | }
45 | if (strFind && (lstMatches.length == 0)) {
46 | lstMatches = tree.evaluateNodePath('//\"' + strFind + '\"');
47 | }
48 | if (lstMatches.length) {
49 | lstMatches.forEach(function(varNode) {
50 | lstRanges.push(tree.createRangeFromNodes(
51 | varNode, 0, varNode, -1));
52 | // unfold if this range is hidden
53 | if (editor.nodeIsHiddenInFold(varNode)) {
54 | editor.expandToRevealNode(varNode);
55 | }
56 | });
57 | editor.setSelectedRanges(lstRanges);
58 | //Make sure that at least the first of any selections is visible
59 | editor.scrollRangeToVisible(lstRanges[0]);
60 | }
61 | } else {
62 |
63 | // make any selection specified by line number etc
64 | if (strLine = getValue('line')) {
65 | lngLine = parseInt(strLine, 10);
66 | if (!(isNaN(lngLine))) {
67 | oNode = tree.lineNumberToNode(lngLine);
68 | if (editor.nodeIsHiddenInFold(oNode)) {
69 | editor.expandToRevealNode(oNode);
70 | editor.scrollToLine(lngLine);
71 | }
72 |
73 | if (strStartOffset = getValue('startoffset')) {
74 | varStartOffset = parseInt(strStartOffset, 10);
75 | if (!isNaN(varStartOffset)) {
76 | lngStartOffset = varStartOffset;
77 | }
78 | }
79 |
80 | if (strEndOffset = getValue('endoffset')) {
81 | varEndOffset = parseInt(strEndOffset, 10);
82 | if (!isNaN(varEndOffset)) {
83 | lngEndOffset = varEndOffset;
84 | }
85 | }
86 |
87 | rngSeln = tree.createRangeFromNodes(
88 | oNode, lngStartOffset, oNode, lngEndOffset);
89 | editor.setSelectedRange(rngSeln);
90 | }
91 | }
92 | }
93 | }
94 | "
on open location strURL
set recParse to pathAndSwitches(strURL)
if recParse is not missing value then
set strPath to Decode(filepath of recParse)
tell application "FoldingText"
set oDoc to (open strPath)
tell oDoc
set varResult to (evaluate script pjsSelect with options (recParse & {keys:plstKeys}))
activate
end tell
end tell
end if
end open location
--on Decode(strEncodedPath)
-- set strCMD to "JSC=/System/Library/Frameworks/JavaScriptCore.framework/Versions/A/Resources/jsc
--\"$JSC\" -e \"print(decodeURI('" & strEncodedPath & "'));\""
-- return do shell script strCMD
--end Decode
on Decode(strEncodedPath)
set strCMD to "
95 | urldecode() {
96 | local url_encoded=\"${1//+/ }\"
97 | printf '%b' \"${url_encoded//%/\\x}\"
98 | }
99 | urldecode '" & strEncodedPath & "'"
return do shell script strCMD
end Decode
on pathAndSwitches(strURL)
-- we can't simply split on '?' as there may be '?' in the text
-- extracting the file in .js would require an active document,
-- so we do it here to save the time and distraction caused by creating one
set strSwitches to ""
set {dlm, my text item delimiters} to {my text item delimiters, "ftdoc://"}
set lstParts to text items of strURL
if length of lstParts < 2 then
set varParse to missing value
else
set strTarget to item 2 of lstParts
set lngFull to length of strTarget
set lngClosest to lngFull
repeat with varKey in plstKeys
set my text item delimiters to ("?" & varKey & "=")
set lstParts to text items of strTarget
if length of lstParts > 1 then
set lngPosn to length of item 1 of lstParts
if lngPosn < lngClosest then set lngClosest to lngPosn
end if
end repeat
set strPath to text 1 thru lngClosest of strTarget
if lngClosest < lngFull then
set strSwitches to text (lngClosest + 1) thru -1 of strTarget
end if
set varParse to {filepath:strPath, switches:strSwitches}
end if
set my text item delimiters to dlm
return varParse
end pathAndSwitches
---- "ftdoc://encoded-file-path[?nodepath=//@due][?line=N][?startoffset=0][?endoffset=-1]"
--------------------------------------------------------------------------------
/utilities/SafariClippings.applescript:
--------------------------------------------------------------------------------
1 | function run() {
2 | var dct = {
3 | title: "Append Safari clipboard to end of file",
4 | ver: "0.4",
5 | description: "Creates MD header with page title, url & timestamp",
6 | author: "RobTrew copyright 2014",
7 | license: "MIT",
8 | site: "https://github.com/RobTrew/txtquery-tools"
9 | };
10 |
11 | var appSafari = Application("Safari");
12 | if (appSafari.windows.length < 1) return 'No windows open in Safari ...';
13 |
14 | var dctOptions = {
15 | $today:fmtTP(new Date(),false),
16 | clipfile:"notes-{$today}.txt", // or just 'clippings.txt' etc
17 | clipfolder: "$HOME/Library/Application Support/Notational Velocity/",
18 | clipheadings: "### ",
19 | urlprefix: "- ",
20 | cliptimetag: "clip",
21 | useNSnotification: false, // turn off for KeyBoard Maestro
22 | clippedsound: 'Pop',
23 | problemsound: 'Blow'
24 | };
25 | //ALTERNATIVE SOUND NAMES
26 | //Basso Frog Hero Pop Submarine
27 | //Blow Funk Morse Purr Tink
28 | //Bottle Glass Ping Sosumi
29 |
30 | //PREPARE FOR ANY NOTIFICATION
31 | ObjC.import('Cocoa');
32 | try {
33 | ObjC.registerSubclass({
34 | name: 'BriefNotify',
35 | methods: {
36 | 'userNotificationCenter:shouldPresentNotification:': {
37 | types: ['bool', ['id', 'id']],
38 | implementation: function (center, notification) {
39 | return true;
40 | }
41 | }
42 | }
43 | });
44 | } catch (e) {} // already defined
45 |
46 |
47 |
48 |
49 | var app = Application.currentApplication(),
50 | oWindow = appSafari.windows[0],
51 | oTab = oWindow.currentTab,
52 | strName = oWindow.name(),
53 | strURL = oTab.url(),
54 | strLink = '[' + strName + '](' + strURL + ')',
55 | strSetUTF8='LANGSTATE="$(defaults read -g AppleLocale).UTF-8"; if [[ "$LC_CTYPE" != *"UTF-8"* ]]; then export LC_ALL="$LANGSTATE" ; fi; ',
56 | strHeading, strRefce, strCmd,
57 | strClip = '',
58 | strPath, strQuotedPath='',
59 | oBriefNotify = $.BriefNotify.alloc.init,
60 | strMsg, strDetail, strSound = '',
61 | strLastPage='',
62 | strTag='@' + dctOptions.cliptimetag + "(" + fmtTP(new Date()) + ")",
63 | varResult;
64 |
65 | function expandTokens(strSource, dctTokens) { //patterns like {$token} replaced by value of dctTokens.$token
66 | var rgxToken = /\{(\$\w+)\}/g,
67 | strTrans = strSource,
68 | oMatch=rgxToken.exec(strSource);
69 |
70 | while (oMatch) {
71 | strTrans=strTrans.replace(oMatch[0], dctTokens[oMatch[1]]);
72 | oMatch=rgxToken.exec(strSource);
73 | }
74 | return strTrans;
75 | }
76 |
77 |
78 | function makePath(strFolder, strFileName) {
79 | var strCMD = 'fldr=$(echo "' + strFolder + '"); if [ -e \"$fldr\" ]; then echo $fldr; fi',
80 | strPath=app.doShellScript(strCMD).trim(),
81 | strFullPath='';
82 |
83 | if (strPath) {
84 | if (strPath[strPath.length-1]==='/')
85 | strFullPath=strPath+strFileName
86 | else strFullPath=strPath+'/'+strFileName
87 | };
88 | return strFullPath;
89 | }
90 |
91 | // Taskpaper-style datetime stamp yyy-mm-dd HH:MM
92 | function fmtTP(dte, blnTime) {
93 | var strDate = '',
94 | strDay = '',
95 | strTime = '',
96 | blnAddTime=(typeof blnTime)==='undefined'?true:blnTime;
97 |
98 |
99 | strDay = [dte.getFullYear(), ('0' + (dte.getMonth() +
100 | 1)).slice(-2), ('0' + dte.getDate()).slice(-2)].join('-');
101 | strTime = [('00' + dte.getHours()).slice(-2), ('00' +
102 | dte.getMinutes()).slice(-2)].join(':');
103 | if (blnAddTime && (strTime !== '00:00')) strDate = [strDay, strTime].join(' ');
104 | else strDate = strDay;
105 | return strDate;
106 | }
107 |
108 | // single quoting for bash shell
109 | function shellEscaped(cmd) {
110 | return '\'' + cmd.replace(/\'/g, "'\\''") + '\'';
111 | }
112 |
113 |
114 |
115 |
116 | function postNote(strTitle, txtInfo, strSoundName) {
117 | var noteFlash = $.NSUserNotification.alloc.init,
118 | strSound = strSoundName || 'Glass';
119 |
120 | noteFlash.title = strTitle;
121 | noteFlash.informativeText = txtInfo;
122 | noteFlash.soundName = strSound;
123 | $.NSUserNotificationCenter.defaultUserNotificationCenter.deliverNotification(noteFlash);
124 | }
125 |
126 | function selnAsHTML() {
127 | var selnWin = window.getSelection(),
128 | lng = selnWin.rangeCount,
129 | oDiv;
130 |
131 | if (lng) {
132 | oDiv = document.createElement('div');
133 | for (var i = 0; i < lng; i++) {
134 | oDiv.appendChild(selnWin.getRangeAt(i).cloneContents());
135 | }
136 | return oDiv.innerHTML;
137 | }
138 | return '';
139 | }
140 |
141 |
142 | app.includeStandardAdditions=true;
143 |
144 | strFullFileName=expandTokens(dctOptions.clipfile, dctOptions);
145 |
146 | strPath = makePath(dctOptions.clipfolder, strFullFileName);
147 | if (strPath) strQuotedPath = '"' + strPath + '"'
148 | else return "Folder not found"
149 |
150 | // Get most recent link (if any, in clippings file)
151 | strCMD="CLIPFILE=" + strQuotedPath + ";if [ -e \"$CLIPFILE\" ]; then cat -n \"$CLIPFILE\" | sort -t: -k 1nr,1 | grep -o -m 1 \'\\[.*\\](.*)\' ; fi"
152 | //return strCMD;
153 | try {
154 | strLastPage=app.doShellScript(strCMD);
155 | } catch (e) { strLastPage=''};
156 |
157 |
158 | // Get the selected HTML
159 |
160 |
161 |
162 |
163 | if (strLastPage !== strLink) {
164 | // Creating new heading from web page name and MD link to URL
165 | strHeading = dctOptions.clipheadings + strName;
166 | strRefce = dctOptions.urlprefix + strLink;
167 | strClip = [strHeading, strRefce, ''].join('\n') + '\n\n';
168 |
169 | // and append heading and clipboard text to the end of the file
170 | strCMD = strSetUTF8 + 'echo ' +
171 | shellEscaped(strClip) + ' >> ' + strQuotedPath +'; pbpaste -Prefer txt >> ' +
172 | strQuotedPath + ' ; printf " ' + strTag + '\n\n" >> ' + strQuotedPath;
173 | } else {
174 | strCMD = strSetUTF8 + 'pbpaste -Prefer txt >> ' + strQuotedPath + ' ; printf " ' + strTag + '\n\n" >> ' + strQuotedPath;
175 | }
176 |
177 |
178 | try {
179 | varResult = app.doShellScript(strCMD);
180 | } catch (e) {
181 | varResult = e.message;
182 | }
183 |
184 | if (!varResult) {
185 | strMsg = "Appended to " + dctOptions.clipfile;
186 | strDetail = strLink;
187 | strSound = dctOptions.clippedsound;
188 | } else {
189 | strMsg = "NOT clipped ...";
190 | strDetail = varResult;
191 | strSound = dctOptions.problemsound;
192 | }
193 |
194 | if (dctOptions.useNSnotification) {
195 | $.NSUserNotificationCenter.defaultUserNotificationCenter.delegate = oBriefNotify;
196 | postNote(strMsg, strDetail, strSound);
197 | }
198 | return strFullFileName;
199 |
200 | }
--------------------------------------------------------------------------------
/tp3doc url scheme and TP3CopyAsURL/Source and info.plist for OpenTP3DocAtLine/OpenTP3DocAtLine.applescript:
--------------------------------------------------------------------------------
1 | property pTitle : "Register and handle tp3doc:// url scheme"
property pVer : "0.04"
property pAuthor : "Rob Trew"
property pDescription : "
2 |
3 | Use in conjunction with the 'TP3CopyAsURL' Applescript to get
4 | a URL which opens the specified document, optionally restoring selection and filter state.
5 |
6 | "
-- Registers the url-scheme tp3doc://encoded-file-path with optional switches:
--[?nodepath=//@due] -- nodepath used to apply a filter
--[?selnpath=] -- nodepath used to specify a selection
--[?find=] -- text string to find
--[?line=N][?startoffset=0][?endoffset=-1]
-- where line is zero-based and defaults to 0
-- startoffset is an offset of a number of characters from the start of the line
-- endoffset is ditto
-- and the url opens the document in TaskPaper:
-- 1. Applying any specified ?nodepath= value as a filter
-- 2. Selecting the first line that matches (in the following order)
-- -- the value of ?selnpath= ?find= or ?line=
-- 3. Restricts the selection to a subset of a line selected by number if startoffset > 0 or endoffset ≠ -1
-- for the approach to registering and handling a url with an applescript.app and the .plist in its bundle,
-- see http://www.macosxautomation.com/applescript/linktrigger/
property piNodePath : 1
property piSelnPath : 2
property piFindText : 3
property piLine : 4
property piStartOffset : 5
property piEndOffset : 6
property plstKeys : {"nodepath", "selnpath", "find", "line", "startoffset", "endoffset"}
property plngKeys : length of plstKeys
property pjsSelect : "
7 |
8 | function(editor, options) {
9 | function getValue(strSwitch) {
10 | return lstSwitches[lstSwitches.indexOf('?' + strSwitch + '=')+1];
11 | }
12 |
13 | var tree= editor.tree(),
14 | oNode, rngSeln,
15 | //options.filepath, options.switches, options.keys
16 | lstKeys = options.keys,
17 | strRegex = '(\\\\?' + lstKeys.join('=|\\\\?') + '=)',
18 | oRegex = new RegExp(strRegex, 'g'),
19 | strPath = decodeURIComponent(options.filepath),
20 | strSwitches = decodeURIComponent(options.switches),
21 | lstSwitches = strSwitches.split(oRegex),
22 | strPath, strLineNum,
23 | strSelnPath,
24 | strFind,
25 | strStartOffset, strEndOffset,
26 | lngLine, lngStartOffset=0, lngEndOffset=-1,
27 | varStartOffset, varEndOffset,
28 | lstMatches=[], lstRanges=[], i;
29 |
30 |
31 | // Try to restore any selection that is specified
32 | if (strPath = getValue('nodepath')) {
33 | //restore any filter
34 | editor.setNodePath(strPath);
35 | }
36 |
37 |
38 | strSelnPath = getValue('selnpath');
39 | strFind = getValue('find');
40 |
41 | if (strSelnPath || strFind) {
42 | if (strSelnPath) {
43 | lstMatches = tree.evaluateNodePath(strSelnPath);
44 | }
45 | if (strFind && (lstMatches.length == 0)) {
46 | lstMatches = tree.evaluateNodePath('//\"' + strFind + '\"');
47 | }
48 | if (lstMatches.length) {
49 | lstMatches.forEach(function(varNode) {
50 | lstRanges.push(tree.createRangeFromNodes(
51 | varNode, 0, varNode, varNode.line().length));
52 | // unfold if this range is hidden
53 | if (editor.nodeIsHiddenInFold(varNode)) {
54 | editor.expandToRevealNode(varNode);
55 | }
56 | });
57 | editor.setSelectedRanges(lstRanges);
58 | //Make sure that at least the first of any selections is visible
59 | editor.scrollRangeToVisible(lstRanges[0]);
60 | }
61 | } else {
62 |
63 | // make any selection specified by line number etc
64 | if (strLine = getValue('line')) {
65 | lngLine = parseInt(strLine, 10);
66 | if (!(isNaN(lngLine))) {
67 | oNode = tree.lineNumberToNode(lngLine);
68 | if (editor.nodeIsHiddenInFold(oNode)) {
69 | editor.expandToRevealNode(oNode);
70 | editor.scrollToLine(lngLine);
71 | }
72 |
73 | if (strStartOffset = getValue('startoffset')) {
74 | varStartOffset = parseInt(strStartOffset, 10);
75 | if (!isNaN(varStartOffset)) {
76 | lngStartOffset = varStartOffset;
77 | }
78 | }
79 |
80 | if (strEndOffset = getValue('endoffset')) {
81 | varEndOffset = parseInt(strEndOffset, 10);
82 | if (!isNaN(varEndOffset)) {
83 | lngEndOffset = varEndOffset;
84 | }
85 | }
86 |
87 | rngSeln = tree.createRangeFromNodes(
88 | oNode, lngStartOffset, oNode, lngEndOffset);
89 | editor.setSelectedRange(rngSeln);
90 | }
91 | }
92 | }
93 | }
94 | "
on run
open location "tp3doc:///Users/robintrew/Desktop/Here%20we%20have%20a%20doc.taskpaper"
end run
on open location strURL
set recParse to pathAndSwitches(strURL)
if recParse is not missing value then
set strPath to urldecode(filepath of recParse)
tell application "TaskPaper"
set oDoc to (open strPath)
tell oDoc
set varResult to (evaluate script pjsSelect with options (recParse & {keys:plstKeys}))
activate
end tell
end tell
end if
end open location
on pathAndSwitches(strURL)
-- we can't simply split on '?' as there may be '?' in the text
-- extracting the file in .js would require an active document,
-- so we do it here to save the time and distraction caused by creating one
set strSwitches to ""
set {dlm, my text item delimiters} to {my text item delimiters, "tp3doc://"}
set lstParts to text items of strURL
if length of lstParts < 2 then
set varParse to missing value
else
set strTarget to item 2 of lstParts
set lngFull to length of strTarget
set lngClosest to lngFull
repeat with varKey in plstKeys
set my text item delimiters to ("?" & varKey & "=")
set lstParts to text items of strTarget
if length of lstParts > 1 then
set lngPosn to length of item 1 of lstParts
if lngPosn < lngClosest then set lngClosest to lngPosn
end if
end repeat
set strPath to text 1 thru lngClosest of strTarget
if lngClosest < lngFull then
set strSwitches to text (lngClosest + 1) thru -1 of strTarget
end if
set varParse to {filepath:strPath, switches:strSwitches}
end if
set my text item delimiters to dlm
return varParse
end pathAndSwitches
-- based on http://harvey.nu/applescript_url_decode_routine.html
on urldecode(theText)
set sDst to ""
set sHex to "0123456789ABCDEF"
set i to 1
repeat while i ≤ length of theText
set c to character i of theText
if c = "+" then
set sDst to sDst & " "
else if c = "%" then
if i > ((length of theText) - 2) then
tell application "System Events"
activate
display dialog ("Invalid URL Encoded string - missing hex char") buttons {"OK"} default button "OK" with title pTitle & " ver. " & pVer
end tell
return ""
end if
set iCVal1 to (offset of (character (i + 1) of theText) in sHex) - 1
set iCVal2 to (offset of (character (i + 2) of theText) in sHex) - 1
if iCVal1 = -1 or iCVal2 = -1 then
tell application "System Events"
activate
display dialog ("Invalid URL Encoded string - not 2 hex chars after % sign") buttons {"OK"} default button "OK" with title pTitle & " ver. " & pVer
end tell
return ""
end if
set sDst to sDst & (ASCII character (iCVal1 * 16 + iCVal2))
set i to i + 2
else
set sDst to sDst & c
end if
set i to i + 1
end repeat
return sDst
end urldecode
-- "tp3doc://encoded-file-path[?nodepath=//@due][?line=N][?startoffset=0][?endoffset=-1]"
--------------------------------------------------------------------------------
/perspectives.ftplugin/README.md:
--------------------------------------------------------------------------------
1 | #### NAME
2 | **txtquery** -- grouped and sorted queries of sets of `@key(value)` tagged [FoldingText/TaskPaper](http://www.foldingtext.com) files
3 |
4 | #### TWO VERSIONS
5 | 1. FoldingText .ftplugin + an Applescript which uses it.
6 | 2. A shell script
7 |
8 | The **plugin** and its **Applescript** are useful for experimenting with TXTQUERY custom perspectives/reports, but only generate perspectives for the current document that is open in FoldingText.
9 |
10 | The **Shell script** uses the [FoldingText CLI tool](https://www.npmjs.org/package/foldingtext) and the [TXTQuery.js](https://github.com/RobTrew/txtquery-tools/tree/master/perspectives.ftplugin) file, and generates grouped and sorted reports across several different text files.
11 |
12 | ###### Shared ViewMenu.json
13 |
14 | Both (plugin/applescript and shell script) can use the same [ViewMenu.json](https://github.com/RobTrew/txtquery-tools/blob/master/perspectives.ftplugin/ViewMenu.json) file (created in the script folder when either is first run). You can inspect this file in a text editor, and tweak existing report templates (FLOWR queries), or even add new ones).
15 |
16 | (Probably simplest, of course, to make a duplicate of an existing FLOWR, give it a new name, and adjust and test it incrementally).
17 |
18 | #### SHELL SCRIPT SYNOPSIS
19 | txtquery.sh [-m] [-r report name|index] [-q query name|index] [options]
20 | #### SHELL SCRIPT DESCRIPTION
21 | **txtquery** generates Markdown-formatted custom reports by applying FLWOR-style queries to sets of `@key(value)` tagged text files.
22 |
23 | The [FLWOR](http://en.wikipedia.org/wiki/FLWOR) queries which it uses are stored in .json menu files. These use [FoldingText](http://www.foldingtext.com) nodepath syntax (FoldingText > Help > NodePaths Guide) to filter text nodes by their tags, values, and text content, and can also include clauses like:
24 |
25 | - Let
26 | - Grouped By ([as in Xquery 3](http://www.w3.org/TR/xquery-30-use-cases/#groupby))
27 | - Order by
28 | - Return (optionally nested)
29 |
30 |
31 | (Note that the tag and text filtering is all done by FoldingText nodepaths, rather than by WHERE clauses)
32 |
33 | Each query FLWOR may also contain a description of the set(s) of text files to which it will be applied.
34 | If a query lacks a 'Sources' clause, then it can fall back to:
35 |
36 | 1. Any defaults sources clause in the menu file, or (in the absence of a menu-level sources clause)
37 | 2. to any defaults sources defined at the head of this script.
38 |
39 | All of these defaults for source text files can, however, be overriden by command line source switches (see below)
40 | including `-mtime` (last modified) and other Bash `find` command filter switches.
41 |
42 | For installation, and more detail on sources etc, see below.
43 |
44 | #### SHELL SCRIPT OPTIONS
45 |
46 | -h help - display this help string
47 | -c collections (paths or globs) - sets of text files to query
48 | -d documents (paths or globs) - documents to query
49 | -f file (path to an alternative ViewMenu.json)
50 | -i include a in the report
51 | -k Marked - view the report in [Marked](http://markedapp2.com)
52 | -l last modified (N[smhdw]) - only query files last modified within period
53 | -m menu - display the menu of report types in ViewMenu.json (or of -f above)
54 | -o output (path) - target file path for report (default is STDOUT)
55 | -r report (name|index) - generate a report of the type named or indicated
56 | -s switches (string) - additional source text switches for Bash Find
57 | -t types of file (comma delimited extension list like 'txt,md,ft')
58 | -v print version numbers of script(s) and FoldingText CLI
59 | -q query (name|index) output the FLWOR definition of the indicated type
60 |
61 | #### INSTALLATION AND DEPENDENCIES
62 |
63 | ##### FoldingText plugin and Applescript
64 |
65 | Requires: [Perspectives.ftplugin folder](https://github.com/RobTrew/txtquery-tools) and its contents, [ftdoc:// url scheme]((https://github.com/RobTrew/txtquery-tools) )
66 |
67 | 1. Copy the Perspectives.ftplugin folder and its contents to the FT ‘Application Folder’ (FoldingText > File > Application Folder)
68 | 2. Close and restart FoldingText
69 | 3. Check in FoldingText > Plugin manager that the Perspectives plugin installed without errors
70 | 4. Open a @key(value) tagged document in FoldingText
71 | 4. Run the Perspectives Applescript, and choose one of the Group by Tags perspectives from the menu
72 |
73 | ##### txtquery.sh shell script for FT CLI
74 |
75 | Requires: [TXTQuery.js](https://github.com/RobTrew/txtquery-tools/tree/master/perspectives.ftplugin), [ftdoc:// url scheme](https://github.com/RobTrew/txtquery-tools), [FoldingText CLI plugin](https://www.npmjs.org/package/foldingtext)
76 |
77 | 1. Copy TXTQuery.js to the same folder as this script
78 | 2. Follow instructions at https://www.npmjs.org/package/foldingtext to install the FT CLI
79 | 3. At the top of this script edit the value of PathToFT to match the path of the FT executable on your system.
80 | 4. In terminal.app, cd to the folder containing this script, and make it executable (chmod +x ./txtquery.sh)
81 |
82 | #### HOW IT WORKS
83 |
84 | The set of specified files is concatenated together into a temporary snowball, which is read by the
85 | [FoldingText CLI tool](https://www.npmjs.org/package/foldingtext) into a FoldingText parse tree.
86 |
87 | This allows for FoldingText nodepath filtering, to which a FoldingText .js script adds nested grouping and sorting by tags and their values. Tracking the size and position of each component file in the snowball also makes it possible for lines in the generated reports to contain hyperlinks (ftdoc:// tp3doc://) back to particular source documents and the corresponding lines within them.
88 |
89 | FLWOR 'Return' clauses allow complete flexibility in the formatting (Markdown or other), of headings subheadings and data linesin the generated reports. A command line switch provides the option of viewing the output reports in Brett Terpstra's [Marked](http://markedapp2.com) as soon as they are generated.
90 |
91 | #### AVOID QUERYING THE REPORT FILES :-)
92 |
93 | Reports, like their sources, are plain text files, and may conceivably contain tags. To avoid circularity and ballooning duplication, it's sensible to make sure that your report output paths are not included in your report source paths :-)
94 |
95 | #### DEFINING SOURCES
96 | ##### Collections
97 | Any paths listed (comma-delimited) under the *collections* key of a query source (or specified on the command line with a `-c` switch) are interpreted as references to SETS of documents.
98 |
99 | 1. A globbed path (ending in *, for example) will be expanded to a list of files
100 | 2. A folder path will be expanded to a list of the folder contents (bash find -maxdepth N can be added with the -s switch).
101 | 3. If the path is to a single text file, that file will be assumed to contain a simple list of paths, each of which will be queried.
102 |
103 | ##### Documents
104 | Any paths listed (comma-delimited) under the *documents* key of a query source (or specified on the command line with a `-d` switch) are interpreted as *direct* references to text files to be queried.
105 | Globs and folders will still be expanded, any path is to single text file, it will be treated as a source to be queried, rather than being read as a list of paths to query.
106 |
107 |
108 | #### Syntax of the FLWOR queries
109 |
110 | - Essentially an initial sketch of a small subset of XQUERY 3 FLOWR, in JSON format, but not yet documented.
111 | - It may be quicker to describe a query or report template to me (Rob Trew @complexpoint on Twitter), and get me to quickly sketch it, than to struggle inductively with the (still rough) syntax yourself :-)
112 |
--------------------------------------------------------------------------------
/perspectives.ftplugin/ViewMenu.json:
--------------------------------------------------------------------------------
1 | {
2 | "sources": {
3 | "collections": "~/Library/Application Support/Notational Velocity/project*",
4 | "docs": "~/Library/Application Support/Notational Velocity/inbox.txt",
5 | "filetypes": "txt,md,ft",
6 | "switches": "-maxdepth 1",
7 | "mtime": "14"
8 | },
9 | "menu": {
10 | "Done by date": {
11 | "sources": {
12 | "mtime": [
13 | "7"
14 | ]
15 | },
16 | "title": "## Done (by date)",
17 | "for": "$items in //@done",
18 | "let": [
19 | "$date = fn:daypart($items@done)",
20 | "$project = $items@project"
21 | ],
22 | "groupby": "$date",
23 | "orderby": "$date",
24 | "return": [
25 | "### {$date}",
26 | {
27 | "for": "$i in $items",
28 | "orderby": "$project",
29 | "return": "- {$i@text} {$i@tags}"
30 | },
31 | ""
32 | ]
33 | },
34 | "Grouped by tag III": {
35 | "title": "## Tags and their values",
36 | "for": "$tag in fn:tagSet()",
37 | "let": "$items = //@{$tag}",
38 | "orderby": "$tag",
39 | "return": [
40 | "### fn:sentence_case({$tag})",
41 | {
42 | "for": "$i in $items",
43 | "let": "$val = $i@{$tag}",
44 | "groupby": "$val",
45 | "orderby": "$val",
46 | "return": [
47 | "{$val}",
48 | {
49 | "for": "$j in $i",
50 | "return": "[{$j@file} line {$j@linenum}]({$j@link})\t- {$j}"
51 | },
52 | ""
53 | ]
54 | },
55 | ""
56 | ]
57 | },
58 | "Grouped by tag II": {
59 | "for": "$tag in fn:tagSet()",
60 | "let": "$items = //@{$tag}",
61 | "orderby": "$tag",
62 | "return": [
63 | "#### fn:sentence_case({$tag}) (fn:count($items))",
64 | {
65 | "for": "$i in $items",
66 | "let": "$val = $i@{$tag}",
67 | "orderby": "$val",
68 | "return": "{$val} - {$i}"
69 | },
70 | ""
71 | ]
72 | },
73 | "Grouped by tag": {
74 | "sources": {
75 | "collections": "~/Library/Application Support/Notational Velocity/project*",
76 | "docs": "~/Library/Application Support/Notational Velocity/inbox.txt",
77 | "filetypes": [
78 | "txt",
79 | "md",
80 | "ft"
81 | ],
82 | "mtime": "42d",
83 | "switches": "-maxdepth 1"
84 | },
85 | "for": "$tag in fn:tagSet()",
86 | "let": "$items = //@{$tag}",
87 | "orderby": "$tag",
88 | "return": [
89 | "#### fn:sentence_case({$tag}) (fn:count($items))",
90 | {
91 | "for": "$item in //@{$tag}",
92 | "return": "- {$item} ({$item@$tag})"
93 | },
94 | ""
95 | ]
96 | },
97 | "Simple sort": {
98 | "title": "### Testing empty sort order",
99 | "for": "$line in //@type!=empty",
100 | "let": "$level = $line@priority",
101 | "orderby": "$level",
102 | "return": "- fn:sentence_case({$line@text}) {$level}"
103 | },
104 | "Grouped by any old tags": {
105 | "for": "$tag in fn:tagSet()",
106 | "let": "$lines = //@{$tag}",
107 | "return": [
108 | "### fn:sentence_case({$tag}) (fn:count($lines) items)",
109 | {
110 | "for": "$i in $lines",
111 | "let": "$value = $i@{$tag}",
112 | "groupby": "$value",
113 | "orderby": "$value",
114 | "return": [
115 | "\t{$value}",
116 | {
117 | "for": "$j in $i",
118 | "return": "\t\t- {$j}"
119 | },
120 | ""
121 | ]
122 | },
123 | ""
124 | ]
125 | },
126 | "Dates with priority subsections": {
127 | "title": "## Dates by priority",
128 | "for": "$line in //@type!=empty",
129 | "let": "$due = fn:daypart($line@due)",
130 | "groupby": "$due",
131 | "orderby": "$due",
132 | "return": [
133 | "### Due {$due}",
134 | "",
135 | {
136 | "for": "$item in $line",
137 | "let": "$level = $item@priority",
138 | "groupby": "$level",
139 | "orderby": "$level asc",
140 | "return": [
141 | "#### Priority ({$level})",
142 | {
143 | "for": "$i in $item",
144 | "let": "$time = fn:timepart($i@due)",
145 | "orderby": "$i@due",
146 | "return": "- {$time} {$i}"
147 | },
148 | ""
149 | ]
150 | },
151 | ""
152 | ]
153 | },
154 | "Grouped by due date and priority": {
155 | "for": "$line in //@priority and @due",
156 | "let": "$level = $line@priority, $due = fn:daypart($line@due)",
157 | "groupby": "$due, $level",
158 | "orderby": "$due, $level",
159 | "return": [
160 | "#### Due {$due} (Priority {$level})",
161 | {
162 | "for": "$i in $line",
163 | "return": "- fn:timepart({$i@due}) {$i}"
164 | },
165 | ""
166 | ]
167 | },
168 | "Due this week (with NVALT links)": {
169 | "title": "## This WEEK",
170 | "for": "$item in //@due <= {today + 7d}",
171 | "let": "$day = fn:daypart($item@due)",
172 | "groupby": "$day",
173 | "orderby": "$day",
174 | "return": [
175 | "### {$day}",
176 | {
177 | "for": "$i in $item",
178 | "orderby": "$i@due",
179 | "return": "- fn:timepart({$i@due}) [{$i}](nvalt://fn:encode_for_uri({$i}))"
180 | },
181 | ""
182 | ]
183 | },
184 | "Overdue with ftdoc links": {
185 | "title": "## This WEEK",
186 | "for": "$item in //@due < {now}",
187 | "let": "$day = fn:daypart($item@due)",
188 | "groupby": "$day",
189 | "orderby": "$day",
190 | "return": [
191 | "### fn:format_date({$day}, '[FNn] [D] [MNn] [Y]'')",
192 | {
193 | "for": "$i in $item",
194 | "orderby": "$i@due",
195 | "return": "- fn:timepart({$i@due}) [{$i}]({$i@url})"
196 | },
197 | ""
198 | ]
199 | },
200 | "Due this week": {
201 | "title": "## This WEEK no links",
202 | "for": "$item in //@due <= {today + 7d}",
203 | "let": "$day = fn:daypart($item@due)",
204 | "groupby": "$day",
205 | "orderby": "$day",
206 | "return": [
207 | "### {$day}",
208 | {
209 | "for": "$i in $item",
210 | "orderby": "$i@due",
211 | "return": "- fn:timepart({$i@due}) {$i}"
212 | },
213 | ""
214 | ]
215 | },
216 | "Allocated time": {
217 | "title": "## Time Allocated",
218 | "for": "$head in /* intersect //@mins/ancestor::*",
219 | "let": "$lines = /{$head}//@mins",
220 | "return": [
221 | "### fn:upper_case({$head}): total fn:sum($lines@mins)m",
222 | {
223 | "for": "$i in $lines",
224 | "return": "- {$i} ({$i@mins}m)"
225 | },
226 | ""
227 | ]
228 | },
229 | "Tagged lines - grouped by tags": {
230 | "for": "$tag in fn:tagSet()",
231 | "return": [
232 | "## fn:sentence_case({$tag})",
233 | {
234 | "for": "$node in //@{$tag}",
235 | "orderby": "$node@{$tag} asc",
236 | "return": "{$node@$tag} - {$node}"
237 | },
238 | ""
239 | ]
240 | },
241 | "Grouped by any priority levels found": {
242 | "title": "### Priorities",
243 | "for": "$line in //@priority",
244 | "let": "$level = $line@priority",
245 | "groupby": "$level",
246 | "orderby": "$level",
247 | "return": [
248 | "### Priority {$level} [fn:sum($line@priority)]",
249 | {
250 | "for": "$node in $line",
251 | "return": "- {$node}"
252 | },
253 | ""
254 | ]
255 | },
256 | "All Nodes simplest sort": {
257 | "for": "$line in //@type!=empty",
258 | "let": "$text=$line",
259 | "orderby": "$text desc",
260 | "return": "- {$text}"
261 | },
262 | "Sorted list with NOTES": {
263 | "for": "$line in //@type=unordered",
264 | "orderby": "$line desc",
265 | "return": [
266 | "- {$line}{$line@note}"
267 | ]
268 | },
269 | "Numbers in sorted in sequence": {
270 | "for": "$num in (10,9,234, 1,2, 5 ,6,7,3,4,8,9)",
271 | "orderby": "$num asc",
272 | "return": "- {$num}"
273 | },
274 | "Tags in sequence": {
275 | "for": "$tag in fn:tagSet()",
276 | "let": "$all = //@{$tag}",
277 | "return": [
278 | "#### fn:sentence_case({$tag}) (fn:count($all))",
279 | {
280 | "for": "$i in $all",
281 | "return": "- {$i}"
282 | },
283 | ""
284 | ]
285 | },
286 | "Tags in document": {
287 | "for": "$tag in fn:tagSet()",
288 | "orderby": "$tag",
289 | "return": "- fn:sentence_case({$tag})"
290 | },
291 | "Grouped by due date": {
292 | "for": "$line in //@due",
293 | "let": "$due = $line@due",
294 | "groupby": "$due",
295 | "orderby": "$due",
296 | "return": [
297 | "## Due {$due}",
298 | {
299 | "for": "$l in $line",
300 | "return": "- {$l@parent} → {$l}"
301 | },
302 | ""
303 | ]
304 | }
305 | },
306 | "queue": []
307 | }
308 |
--------------------------------------------------------------------------------
/utilities/MakeTestData.applescript:
--------------------------------------------------------------------------------
1 | property pTitle : "Make random tagged and nested tasks"
property pDescription : "for testing new plain text queries with txtQuery.sh"
property pVer : "0.03"
property pAuthor : "Rob Trew"
property pblnDebug : false
-- Generates a new foldingtext document populated with a random set of tagged and nested tasks
-- define subset of tags to use by setting true|false in the following record
-- NB if you create any additional tags, you will need to define value lists or functions
-- for them in dctTagVals below either as:
-- 1. An array of possible values e.g. ['alpha', 'beta', 'gamma'] from which a random choice will be made
-- 2. A lambda (anonymous function) which returns a value e.g. function() {return (randomInt(1,19)*5).toString();}
-- 3. The string 'day' for which a random date will be generated
-- 4. The string 'time' for which a random date and time will be generated
-- SET THE RANGE OF DATES WITHIN WHICH RANDOM DATE TAGS WILL BE GENERATED
property pNow : (current date)
property pFrom : pNow - 30 * days
property pTo : pNow + 60 * days
property precRange : {earliest:pFrom, latest:pTo}
property precTags : {activetags:{priority:true, start:true, due:true, mins:true, alert:true, next:true, done:true}}
property pUnixEpoch : missing value
property pstrJS : "
2 | function(editor, options) {
3 | var tree=editor.tree(), oParent=tree.root,
4 | lstSyntax = ['process','affected','instrument','circumstance','time'],
5 | dctTags = options.activetags,
6 | lstTagSet = Object.keys(dctTags),
7 | lstActiveTags=lstTagSet.filter(
8 | function (oTag) {return dctTags[oTag];}),
9 | lngActiveTags=lstActiveTags.length,
10 | iLastTag=lngActiveTags-1,
11 | dctLex={
12 | 'process':['build','make', 'think', 'work', 'drink','give','call', 'try', 'winnow', 'aggregate', 'link', 'derive', 'summarise'],
13 | 'affected':['school','system','program','question','water','book','earth','umbrella','time','thing','world','life','footsoldier','company','problem', 'group', 'number','weaver','toothbrush','derivation','method', 'mountain', 'termite mound'],
14 | 'instrument':['school','system','program','question','water','book','earth','umbrella','time','thing','world','life','footsoldier','company','problem', 'group', 'number','weaver','sandwich', 'theorem', 'hypothesis', 'assumption', 'contradiction', 'function', 'derivation'],
15 | 'circumstance':['at the office', 'in the library', 'at home', 'in the forest', 'on the mountain', 'while commuting', 'at lunch', 'after breakfast', 'before supper', 'tomorrow morning', 'in a boat', 'on the sea', 'by a bridge', 'along the river', 'under the maples', 'with lambda', 'with lemma'],
16 | 'time':['early','on Fridays', 'next week', 'in two days', 'at the end of the month', 'before 2015', 'after 2017','after the harvest','during the spring sowing','after Michaelmas','in Trinity', 'tomorrow', 'this evening', 'at 7pm on Monday', 'by August', 'first thing', 'before retiring']
17 | },
18 |
19 | dteStart=new Date(),
20 | dteHorizon=new Date(),
21 |
22 | dctTagVals={
23 | 'priority':[1, 2, 3],
24 | 'start':'day',
25 | 'alert':'time',
26 | 'due':'time',
27 | 'done':'time',
28 | 'mins':function() {return (randomInt(1,19)*5).toString();}
29 | },
30 |
31 | lngCount, lngPhrase=60, strPhrase='', lstParts=[], lstPhrases=[],lngSyntax=lstSyntax.length,blnTag,
32 | lstWords, lngWords, strKey, iWord, strWord;
33 |
34 | function randomInt(min, max) {
35 | return Math.floor(Math.random() * (max - min + 1)) + min;
36 | }
37 |
38 | function simplePhrase(lngLevel, dteLocalStart, dteLocalDue) {
39 | var strPrefix, strPhrase, lngPhrase,
40 | dteFrom=dteLocalStart, dteTo=dteLocalDue, varTagVal,
41 | strType, varValue, strValue, lngRange,
42 | lstParts = [], lstSeen=[], iTag, dteMoment, lngTags;
43 |
44 |
45 | // CREATE A RANDOM PHRASE
46 | // using only a number of words that matches the nesting level,
47 | lngPhrase=Math.min(lngSyntax, lngLevel);
48 | for (var j=0;j Help > SDK > Run Editor
set varResult to (debug script pstrJS with options recOptions)
end if
end tell
return varResult
end run
on AsDate2JS(dteAs)
if pUnixEpoch is missing value then set pUnixEpoch to UnixEpoch()
return (dteAs - pUnixEpoch) * 1000
end AsDate2JS
on UnixEpoch()
tell (current date)
set {its year, its day, its time} to {1970, 1, 0}
set its month to 1 -- set after day for fear of Feb :-)
return (it + (my (time to GMT)))
end tell
end UnixEpoch
--------------------------------------------------------------------------------
/Yosemite Javascript XQuery demo/QueryAFolderOfOPMLFiles.applescript:
--------------------------------------------------------------------------------
1 | // Simple demonstration of using XQuery from OS X Yosemite Javascript for Applications
2 | // To get a menu of custom perspectives across several files (using OS X (NSXML) XQUERY from Javascript):
3 |
4 | // 1. Copy the accompanying OPML files (tagged with attributes from FoldingText / TaskPaper) into a folder
5 | // 2. Run this script, choosing (from the dialog which pops up) the folder containing the OPML files
6 |
7 |
8 | // Copyright Robin Trew Feb 2015
9 |
10 |
11 | function run() {
12 | 'use strict';
13 | /* jshint multistr: true */
14 |
15 |
16 | // OPEN OUTPUT IN [Marked 2](http://marked2app.com) ?
17 | var blnOpenPerspectiveInMarked = true;
18 |
19 | // OPEN SOURCE FILE FOR SELECTED ACTIONS ?
20 | var blnOpenSelected = false;
21 |
22 | // Temporary output file for "Marked 2.app" to preview
23 | var strTestFile = "~/Desktop/TestXQuery01.txt"; // WILL BE OVERWRITTEN - CHECK THAT THIS DOESN'T CLASH
24 |
25 | // EXTENSION OF FILES TO QUERY
26 | var strExtn = "opml";
27 |
28 | var strExtnUpper = strExtn.toUpperCase();
29 |
30 |
31 | // MENU OF CUSTOM PERSPECTIVES - DEFINED (OVER A SET OF OPML FILES) IN NSXMLNODE XQUERY 1.0
32 | var dctXQuery = {
33 | 'Grouped by Priority level - sorted by descending @due date': ' \
34 | let $v := distinct-values(//outline/@priority) \
35 | for $i in $v \
36 | order by $i \
37 | return ( \
38 | concat("\n### Priority ", $i, ""), \
39 | for $o in //outline[@priority=$i] \
40 | let $d := $o/@due \
41 | order by $d empty greatest \
42 | return ( \
43 | concat( \
44 | "- ", $o/@text, \
45 | if ($d) then concat(" @due(",$d,")") else () \
46 | ) \
47 | ) \
48 | )',
49 |
50 | 'Starting in March': ' \
51 | let $v := distinct-values( \
52 | //outline[@start > "2015-02-30" and @start < "2015-04-01"]/substring(@start,1,10) \
53 | ) \
54 | for $d in $v \
55 | order by $d \
56 | return ( \
57 | concat("\n#### ", substring($d, 1, 7), " ", substring($d, 9), ""), \
58 | for $o in //outline[@start=$d]\
59 | let $r := $o/ancestor::outline[@file], \
60 | $f := $r/@file, \
61 | $fp := $r/@path, \
62 | $t := $o/@text \
63 | order by $t \
64 | return ( \
65 | concat( \
66 | "- ", $t, \
67 | " [", $f, "](file://", $fp, $f, ")" \
68 | ) \
69 | ) \
70 | )',
71 |
72 | 'Immediate priorities': ' \
73 | let $v := distinct-values(//outline[@priority=1 and @due]/substring(@due,1,10)) \
74 | for $d in $v \
75 | let $dte := xs:date($d), \
76 | $e := xs:date("1901-01-06") \
77 | order by $d \
78 | return (\
79 | concat( \
80 | "\n#### ", \
81 | ("Sun", "Mon", "Tue", "Wed","Thu", "Fri", "Sat")[ \
82 | (days-from-duration($dte - $e) mod 7) + 1 \
83 | ], \
84 | " ", substring($d, 1, 7), \
85 | " ", substring($d, 9, 2), " " \
86 | ), \
87 | for $i in //outline[@priority=1 and starts-with(@due, $d)] \
88 | let $it := $i/@due, \
89 | $t := substring($it, 12), \
90 | $tme := if ($t) then xs:time(concat($t, ":00")) else xs:time("00:00:00")\
91 | order by $t empty least \
92 | return concat( \
93 | if ($t) then concat("",$t," ") else (), \
94 | $i/@text \
95 | ) \
96 | )',
97 |
98 |
99 | 'Due and urgent': ' \
100 | for $p in //outline[@priority=1 and @due] \
101 | let $d := $p/@due, \
102 | $r := $p/ancestor::outline[@file], \
103 | $f := $r/@file, \
104 | $fp := $r/@path \
105 | order by $d \
106 | return concat( \
107 | "- ", $p/@text, " ", \
108 | if ($d) then \
109 | concat("@due(", $d, ")") \
110 | else (), \
111 | " [", $f, "](file://", $fp, $f, ")" \
112 | )',
113 |
114 |
115 | 'Projects with alert dates': ' \
116 | for $p in //outline[@type="heading" and @alert] \
117 | let $a := $p/@alert, \
118 | $r := $p/ancestor::outline[@file], \
119 | $f := $r/@file, \
120 | $fp := $r/@path \
121 | order by $a \
122 | return concat( \
123 | "- ", $p/@text, " ", \
124 | "@alert(", $a, ")", \
125 | " [", $f, "](file://", $fp, $f, ")" \
126 | )'
127 | };
128 |
129 | // strPath --> [strFileName]
130 | function filesInFolder(strPath) {
131 | var fm = $.NSFileManager.defaultManager,
132 | lstFiles = ObjC.unwrap(fm.contentsOfDirectoryAtPathError(strPath, null)),
133 | lst = [];
134 |
135 | for (var i = 0, lng = lstFiles.length; i < lng; i++) {
136 | lst.push(ObjC.unwrap(lstFiles[i]));
137 | }
138 | return lst;
139 | }
140 |
141 | // strFolderPath --> strExtension --> [strFilePath]
142 | function filesInFolderWithExtn(strPath, strExtn) {
143 | var lst = filesInFolder(strPath),
144 | lstMatch = [],
145 | strBase = (strPath.charAt(strPath.length - 1) === '/') ?
146 | strPath : strPath + '/',
147 | strFileName, lstParts, lngParts;
148 |
149 | for (var i = 0, lng = lst.length; i < lng; i++) {
150 | strFileName = lst[i];
151 | lstParts = strFileName.split('.');
152 | lngParts = lstParts.length;
153 | if ((lngParts > 1) && (lstParts[lngParts - 1] === strExtn))
154 | lstMatch.push(strBase + strFileName);
155 | }
156 | return lstMatch;
157 | }
158 |
159 | // XInclude LIST OF FILES TO INCLUDE IN THE COMPOSITE NSXMLDOCUMENT WHICH WE WILL QUERY
160 | // [filePath] --> strWrapElementName --> strInnerElementName --> strIncludeXML
161 | function xIncludeXML(lstFilePaths, strWrapElement, strInnerElement) {
162 | var lst = [
163 | '',
164 | '<' + strWrapElement + ' xmlns:xi="http://www.w3.org/2003/XInclude">'
165 | ],
166 | strXML;
167 |
168 | function fileEntry(strPath, strElement) {
169 | var lstParts = strPath.split('/'),
170 | strFile = encodeURI(lstParts.pop());
171 |
172 | return [
173 | '\t<' + strElement + ' text="" path="' + encodeURI(lstParts.join(
174 | '/')) +
175 | '/" file="' + strFile + '">',
176 | '\t\t',
177 | '\t' + strElement + '>'
178 | ].join('\n');
179 | }
180 |
181 | i = lstFilePaths.length;
182 | while (i--) {
183 | lst.push(fileEntry(lstFilePaths[i], strInnerElement));
184 | }
185 |
186 | strXML = lst.join('\n') + '\n' + strWrapElement + '>';
187 | //console.log(strXML);
188 | return strXML;
189 | }
190 |
191 |
192 | /////// MAIN ////////////////////////////////////////////////////////////////////////////////////
193 |
194 | var rgxFileURL = /\((file.*)\)$/,
195 | varChoice = true,
196 | oMatch, docXML,
197 | lstMenu, lst, lstFiles,
198 | strURL, strMenuKey, strTitle, strXML, strTXT, strPATH,
199 | lng, i,
200 | blnWritten;
201 |
202 | // PREPARE FOR USE OF DIALOGS
203 | var app = Application.currentApplication();
204 | app.includeStandardAdditions = true;
205 | app.activate();
206 |
207 | // CHOOSE THE FOLDER CONTAINING THE FOUR DEMO .OPML FILES (TAGGED WITH VARIOUS ATTRIBUTE VALUES)
208 | var strFolderPath = app.chooseFolder({
209 | withPrompt: "CHOOSE FOLDER CONTAINING SAMPLE " + strExtnUpper + " FILES"
210 | }).toString();
211 |
212 | // SHOW A MENU OF PERSPECTIVES
213 |
214 | while (varChoice) {
215 | lstMenu = Object.keys(dctXQuery);
216 | varChoice = lstMenu.length ? app.chooseFromList(lstMenu, {
217 | withTitle: "xQuery across several files",
218 | withPrompt: "Select Perspective:",
219 | defaultItems: [lstMenu[0]]
220 | }) : false;
221 |
222 |
223 | // USE THE MENU NAME AS THE REPORT TITLE
224 | strMenuKey = varChoice[0];
225 |
226 |
227 | // REFERENCE EACH FILE IN AN XINCLUDE DOCUMENT
228 | lstFiles = filesInFolderWithExtn(strFolderPath, strExtn);
229 | if (lstFiles.length) {
230 | strXML = xIncludeXML(
231 | filesInFolderWithExtn(strFolderPath, strExtn), 'body', 'outline'
232 | );
233 | } else {
234 | app.displayDialog("No " + strExtnUpper + " files found in " + strFolderPath);
235 | return;
236 | }
237 |
238 | // READ THE XINCLUSIONS INTO A COMPOSITE XML FILE
239 | docXML = $.NSXMLDocument.alloc.initWithXMLStringOptionsError(
240 | strXML, $.NSXMLDocumentXInclude, null
241 | );
242 |
243 | return strXML
244 |
245 | // THEN APPLY THE QUERY ...
246 | lst = ObjC.unwrap(docXML.objectsForXQueryError(
247 | dctXQuery[strMenuKey], null
248 | ));
249 |
250 | // debug return lst for quick harvest check
251 | // return lst;
252 |
253 |
254 | // AND HARVEST ANY RESULT
255 | if (!lst) return;
256 | i = lst.length;
257 | if (i) {
258 | while (i--) lst[i] = ObjC.unwrap(lst[i]);
259 |
260 | if (blnOpenPerspectiveInMarked) {
261 |
262 | // WRITE OUT PERSPECTIVE AS TEXT FILE
263 | strTXT = $.NSString.alloc.initWithUTF8String(
264 | '## ' + strMenuKey + '\n\n' + lst.join('\n')
265 | );
266 |
267 | strPATH = $.NSString.alloc.initWithUTF8String(
268 | strTestFile
269 | );
270 | strPATH = ObjC.unwrap(strPATH.stringByExpandingTildeInPath);
271 |
272 |
273 | blnWritten = strTXT.writeToFileAtomically(strPATH, true);
274 |
275 | // AND OPEN IT IN [MARKED 2](http://marked2app.com)
276 | if (blnWritten) {
277 | app.doShellScript(
278 | 'open -a "Marked 2" ' + strPATH
279 | );
280 | }
281 | } else {
282 |
283 | varChoice = app.chooseFromList(lst, {
284 | withTitle: strMenuKey,
285 | withPrompt: "Select from actions matching [" + strMenuKey + "]:",
286 | defaultItems: lst[0],
287 | multipleSelectionsAllowed: true
288 | });
289 |
290 | // OPEN THE OPML FILE(S) FOR THE CHOSEN ACTION(S) IN THE DEFAULT OPML EDITOR ?
291 | if (blnOpenSelected) {
292 | if (varChoice) {
293 | i = varChoice.length;
294 | while (i--) {
295 | oMatch = rgxFileURL.exec(varChoice[i]);
296 | if (oMatch) {
297 | app.doShellScript('open ' + oMatch[1]);
298 | }
299 | }
300 | break;
301 | }
302 | }
303 | }
304 | } else {
305 | app.displayAlert(
306 | "No matches for " + strMenuKey + " found in " + strFolderPath +
307 | " .opml files"
308 | );
309 | }
310 |
311 | }
312 |
313 |
314 | return true;
315 | }
--------------------------------------------------------------------------------
/Yosemite Javascript XQuery demo/SampleFolder/workProject.txt:
--------------------------------------------------------------------------------
1 |
2 |
3 | # work @alert(2015-02-03 03:00) @start(2015-03-07) @done(2015-02-25) @due(2015-02-26 03:00)
4 |
5 | ## call mountain @priority(1) @status(wait) @alert(2015-02-18 07:30) @start(2015-02-12)
6 | - build school hypothesis @status(wait) @mins(50) @alert(2015-02-12 03:30)
7 | - drink earth book with lambda @due(2015-02-09 12:30) @mins(75) @priority(1) @start(2015-02-27) @alert(2015-02-03 16:00)
8 | - build program number with lemma @due(2015-03-05 04:30) @mins(65) @alert(2015-02-27 05:30) @status(wait) @done(2015-02-06 20:00) @priority(2)
9 | - try group group along the river @alert(2015-02-02 14:00) @due(2015-02-02 23:00) @priority(2) @start(2015-02-25)
10 | - work mountain function @status(throw)
11 | - make group group in the forest @done(2015-03-01 16:00) @due(2015-02-27 15:00) @status(throw) @alert(2015-02-05 05:30) @mins(10)
12 | - think world footsoldier at lunch @start(2015-02-13) @pom(45)
13 | - aggregate life earth before supper @priority(1) @pom(70) @done(2015-03-08 02:00) @due(2015-02-15 21:30) @mins(30) @status(wait)
14 | - work life time @status(throw) @done(2015-02-02 13:30) @mins(60) @priority(3) @alert(2015-02-11 20:00)
15 | - make derivation number by a bridge @start(2015-02-25) @done(2015-02-20 07:00) @status(grade) @mins(70)
16 | - link footsoldier derivation while commuting
17 | - aggregate book derivation by a bridge @start(2015-03-03) @mins(30)
18 |
19 | ## make time @mins(85)
20 | - make derivation contradiction @done(2015-02-22 08:30) @pom(55) @status(grade) @start(2015-02-24) @due(2015-02-13 22:30)
21 | - build group theorem before supper @pom(40) @done(2015-02-18 20:30) @alert(2015-02-21 09:00)
22 | - link world school at the office
23 | - drink earth system along the river @mins(55) @status(wait) @priority(1) @done(2015-02-03 08:30) @alert(2015-02-11 17:00)
24 | - summarise weaver question @done(2015-02-08 18:00) @mins(80) @due(2015-02-02 01:00)
25 | - link program water along the river @alert(2015-02-10 20:00) @pom(15)
26 | - drink water problem in the forest @pom(35) @status(wait) @start(2015-02-11) @mins(75) @done(2015-02-15 04:30) @alert(2015-02-10) @priority(1)
27 | - summarise number theorem with lemma
28 | - winnow program thing @due(2015-02-10 06:00) @priority(1) @pom(70) @done(2015-03-01 23:00) @mins(10) @status(wait) @start(2015-02-28)
29 | - work problem problem by a bridge @priority(3)
30 | - try umbrella life tomorrow morning @priority(1) @done(2015-02-14 11:00) @start(2015-03-01) @alert(2015-02-08 16:30) @mins(90)
31 | - give thing school with lemma @done(2015-02-07 18:00) @start(2015-02-17)
32 |
33 | ## call number @done(2015-02-11) @start(2015-03-04) @mins(30) @due(2015-02-27 07:00) @pom(10) @alert(2015-02-03 11:00)
34 | - link school program @start(2015-02-10) @mins(55) @status(wait) @done(2015-02-18 07:30) @alert(2015-02-04 00:30) @pom(55) @priority(3)
35 | - try toothbrush weaver at the office @status(read) @mins(55) @start(2015-02-20) @priority(3) @done(2015-02-16) @due(2015-02-19 21:00) @pom(5)
36 | - think earth sandwich on the sea @mins(5)
37 | - aggregate group question at home @due(2015-02-10 07:00) @start(2015-02-22) @pom(35) @status(wait)
38 | - build system thing @due(2015-02-27 04:00) @done(2015-03-07 06:00) @priority(3) @pom(5) @mins(70) @start(2015-02-10)
39 | - give program school in the forest @priority(2) @done(2015-03-04 21:30) @status(read) @start(2015-03-07) @pom(15) @mins(95)
40 | - summarise number footsoldier along the river @mins(35) @priority(1)
41 | - think system earth tomorrow morning @priority(3) @done(2015-02-06 17:00) @pom(85)
42 | - call number contradiction @start(2015-02-19)
43 | - give weaver water in the library @priority(1) @pom(30) @done(2015-02-28 11:30) @start(2015-03-02) @mins(30)
44 | - build book theorem after breakfast @priority(3)
45 | - make water number on the sea @start(2015-02-22) @alert(2015-02-18 09:00)
46 |
47 | # link @status(throw)
48 |
49 | ## winnow book @done(2015-02-14 13:00)
50 | - drink termite mound hypothesis @pom(75) @done(2015-02-22 11:00) @status(wait) @mins(45) @due(2015-02-02 20:30) @priority(1)
51 | - aggregate system umbrella along the river
52 | - make school company at the office @mins(65) @status(wait) @alert(2015-02-13 20:30)
53 | - drink derivation company at lunch @pom(40) @alert(2015-02-28 03:00) @mins(15) @start(2015-03-05) @priority(3)
54 | - build problem water @priority(2) @done(2015-02-12 02:00) @alert(2015-02-18 18:00) @mins(60)
55 | - link program book on the sea @due(2015-03-04 03:00) @alert(2015-02-10 13:00) @done(2015-02-26 17:00) @priority(2)
56 | - derive number system with lemma @pom(55)
57 | - work method derivation at lunch @done(2015-02-03 18:30) @mins(70) @alert(2015-02-14 12:00) @pom(40) @status(read) @start(2015-03-06) @priority(1)
58 | - make program function @pom(95) @due(2015-03-01 23:30)
59 | - build toothbrush number on the sea @alert(2015-02-08 01:00)
60 | - try thing weaver in the library
61 | - aggregate world weaver with lambda @due(2015-02-14 16:00) @pom(75) @mins(45)
62 |
63 | ## link umbrella @done(2015-02-21 12:00) @priority(1) @due(2015-03-02 03:00) @alert(2015-02-19 19:30) @mins(60)
64 | - call termite mound number @due(2015-02-14 10:30) @priority(3)
65 | - give company company on the mountain @status(throw) @priority(1) @pom(75) @done(2015-02-25 17:00)
66 | - build number assumption at the office
67 | - make earth weaver by a bridge @start(2015-02-06) @done(2015-03-07 04:00) @priority(1)
68 | - build life book @start(2015-03-04) @priority(1) @done(2015-02-28 04:00)
69 | - drink umbrella world on the sea @start(2015-02-22)
70 | - winnow world derivation under the maples @status(wait) @pom(65)
71 | - build time system along the river @priority(3)
72 | - aggregate derivation question @pom(25) @priority(1) @mins(5)
73 | - winnow weaver company on the sea @done(2015-02-03 11:00) @priority(3)
74 | - build system group with lemma
75 | - summarise world hypothesis with lambda @due(2015-02-13 21:00)
76 |
77 | ## derive program @status(throw) @alert(2015-03-07 10:00)
78 | - drink thing theorem
79 | - try derivation time on the sea @alert(2015-03-06 21:00) @start(2015-02-20) @due(2015-02-15 02:00) @status(throw)
80 | - summarise school book along the river @pom(75) @alert(2015-02-21 20:00) @due(2015-03-08 01:00)
81 | - think number number after breakfast @pom(25) @mins(55) @start(2015-02-24) @due(2015-02-05 15:00)
82 | - derive school book @start(2015-02-23) @due(2015-02-07 13:00) @done(2015-02-22 18:00) @alert(2015-02-23 15:00) @status(grade) @priority(2)
83 | - give mountain number while commuting @priority(3) @pom(10) @alert(2015-03-05 10:30) @done(2015-03-04 20:00) @status(wait) @mins(65)
84 | - build life school in the library @due(2015-02-08 07:00) @status(read) @done(2015-02-28 19:00)
85 | - summarise time footsoldier by a bridge @mins(45) @start(2015-03-01) @priority(2) @due(2015-02-08 03:00) @pom(10) @done(2015-03-05 14:30)
86 | - work book assumption @alert(2015-02-26 22:00) @due(2015-03-03 01:00) @mins(55) @start(2015-02-26) @status(read) @priority(2)
87 | - try school problem before supper @due(2015-02-15 02:00) @done(2015-03-01 04:30) @mins(80) @pom(45) @start(2015-02-20)
88 | - work time contradiction at lunch @mins(75) @pom(40) @done(2015-02-20 19:30) @status(read)
89 | - make company question in a boat
90 |
91 | # call @alert(2015-02-14 09:00) @status(wait) @pom(55) @due(2015-03-02 13:00) @done(2015-03-06 21:00) @priority(3)
92 |
93 | ## make company @mins(75) @status(wait) @pom(30)
94 | - build world book @status(wait) @mins(40) @due(2015-03-08 20:00) @done(2015-02-13 01:30) @priority(2)
95 | - summarise program book at home @start(2015-03-03) @status(throw) @priority(2) @mins(35) @done(2015-02-25 07:00) @due(2015-02-18 23:00)
96 | - link toothbrush company with lemma @due(2015-02-27 16:00) @status(throw) @alert(2015-03-06 14:30) @priority(3)
97 | - try mountain school with lemma @due(2015-02-19 08:00) @alert(2015-02-27 16:00) @mins(45) @status(grade)
98 | - think program company
99 | - link mountain number while commuting @alert(2015-02-08 22:00)
100 | - summarise derivation book on the sea @status(throw) @due(2015-02-13 21:00) @alert(2015-02-27 23:00)
101 | - winnow group system after breakfast @priority(1) @status(grade) @mins(60) @done(2015-02-17 23:00) @due(2015-02-16 05:00) @alert(2015-02-07 15:30) @pom(75)
102 | - aggregate world world @status(throw) @done(2015-02-12 06:30) @pom(30) @mins(90) @alert(2015-03-08 17:30)
103 | - think life company along the river @done(2015-03-03 22:00) @priority(3) @mins(90) @status(grade) @start(2015-02-18)
104 | - give earth umbrella under the maples @priority(2) @mins(60) @due(2015-02-09 23:00)
105 | - derive termite mound system in the library
106 |
107 | ## derive book @status(grade) @mins(70)
108 | - give derivation umbrella @start(2015-02-16) @due(2015-02-15 02:00) @done(2015-03-06 23:30) @alert(2015-02-25 14:00) @pom(80)
109 | - summarise life weaver in the forest @pom(15) @done(2015-02-22 16:00) @start(2015-02-24) @alert(2015-03-06) @status(grade)
110 | - try group program along the river
111 | - work life hypothesis in the forest @due(2015-02-10 14:00) @start(2015-02-04) @status(grade) @pom(70) @priority(3)
112 | - work school group @status(throw) @start(2015-03-01) @mins(80) @alert(2015-02-05 14:00) @due(2015-02-23 02:00)
113 | - aggregate mountain time at the office @pom(80) @due(2015-03-07 19:30) @start(2015-02-22) @mins(25) @done(2015-02-02 16:00) @status(grade) @priority(2)
114 | - try termite mound derivation on the mountain @pom(95) @start(2015-03-08) @alert(2015-02-17 17:00) @mins(60) @priority(1)
115 | - make umbrella number after breakfast @mins(30)
116 | - call water time @status(grade) @pom(45) @priority(1) @alert(2015-02-05 20:00) @mins(60) @due(2015-02-11 18:30) @done(2015-02-21 02:00)
117 | - winnow time world in a boat @pom(40)
118 | - call number group by a bridge @due(2015-02-09 02:30)
119 | - think time contradiction under the maples @done(2015-02-16 04:00)
120 |
121 | ## call school @done(2015-02-16 04:30) @priority(1) @mins(60) @alert(2015-03-02 07:00) @pom(70) @start(2015-02-28) @status(throw)
122 | - work derivation theorem
123 | - give derivation sandwich in a boat
124 | - try number weaver tomorrow morning @done(2015-02-12 18:30) @alert(2015-02-16 19:30)
125 | - link toothbrush group by a bridge @pom(45)
126 | - call umbrella question @pom(95)
127 | - think method question tomorrow morning @alert(2015-02-23 21:00)
128 | - give termite mound hypothesis under the maples @due(2015-03-06 05:00) @done(2015-02-08 17:00)
129 | - work thing derivation at home
130 | - think thing system @status(wait) @done(2015-02-16 06:00) @due(2015-02-10 04:00) @priority(2) @alert(2015-02-28 06:00)
131 | - summarise termite mound function under the maples @mins(20) @priority(3) @due(2015-03-05 14:00)
132 | - give question number on the mountain
133 | - make number weaver after breakfast @due(2015-03-03 16:00)
--------------------------------------------------------------------------------