├── .editorconfig ├── .github └── workflows │ └── release.yml ├── .gitignore ├── .vscode ├── launch.json └── tasks.json ├── LICENSE ├── analysis_options.yaml ├── bin-cache └── noteplan-arm64 ├── bin └── noteplan.dart ├── icons ├── iconsets │ ├── icon-code-bit.iconset │ │ ├── icon_128x128.png │ │ ├── icon_128x128@2x.png │ │ ├── icon_16x16.png │ │ ├── icon_16x16@2x.png │ │ ├── icon_256x256.png │ │ ├── icon_256x256@2x.png │ │ ├── icon_32x32.png │ │ ├── icon_32x32@2x.png │ │ ├── icon_512x512.png │ │ └── icon_512x512@2x.png │ ├── icon-create.iconset │ │ ├── icon_128x128.png │ │ ├── icon_128x128@2x.png │ │ ├── icon_16x16.png │ │ ├── icon_16x16@2x.png │ │ ├── icon_256x256.png │ │ ├── icon_256x256@2x.png │ │ ├── icon_32x32.png │ │ ├── icon_32x32@2x.png │ │ ├── icon_512x512.png │ │ └── icon_512x512@2x.png │ ├── icon-daily.iconset │ │ ├── icon_128x128.png │ │ ├── icon_128x128@2x.png │ │ ├── icon_16x16.png │ │ ├── icon_16x16@2x.png │ │ ├── icon_256x256.png │ │ ├── icon_256x256@2x.png │ │ ├── icon_32x32.png │ │ ├── icon_32x32@2x.png │ │ ├── icon_512x512.png │ │ └── icon_512x512@2x.png │ ├── icon-folder.iconset │ │ ├── icon_128x128.png │ │ ├── icon_128x128@2x.png │ │ ├── icon_16x16.png │ │ ├── icon_16x16@2x.png │ │ ├── icon_256x256.png │ │ ├── icon_256x256@2x.png │ │ ├── icon_32x32.png │ │ ├── icon_32x32@2x.png │ │ ├── icon_512x512.png │ │ └── icon_512x512@2x.png │ ├── icon-hyperlink.iconset │ │ ├── icon_128x128.png │ │ ├── icon_128x128@2x.png │ │ ├── icon_16x16.png │ │ ├── icon_16x16@2x.png │ │ ├── icon_256x256.png │ │ ├── icon_256x256@2x.png │ │ ├── icon_32x32.png │ │ ├── icon_32x32@2x.png │ │ ├── icon_512x512.png │ │ └── icon_512x512@2x.png │ ├── icon-monthly.iconset │ │ ├── icon_128x128.png │ │ ├── icon_128x128@2x.png │ │ ├── icon_16x16.png │ │ ├── icon_16x16@2x.png │ │ ├── icon_256x256.png │ │ ├── icon_256x256@2x.png │ │ ├── icon_32x32.png │ │ ├── icon_32x32@2x.png │ │ ├── icon_512x512.png │ │ └── icon_512x512@2x.png │ ├── icon-note.iconset │ │ ├── icon_128x128.png │ │ ├── icon_128x128@2x.png │ │ ├── icon_16x16.png │ │ ├── icon_16x16@2x.png │ │ ├── icon_256x256.png │ │ ├── icon_256x256@2x.png │ │ ├── icon_32x32.png │ │ ├── icon_32x32@2x.png │ │ ├── icon_512x512.png │ │ └── icon_512x512@2x.png │ ├── icon-quarterly.iconset │ │ ├── icon_128x128.png │ │ ├── icon_128x128@2x.png │ │ ├── icon_16x16.png │ │ ├── icon_16x16@2x.png │ │ ├── icon_256x256.png │ │ ├── icon_256x256@2x.png │ │ ├── icon_32x32.png │ │ ├── icon_32x32@2x.png │ │ ├── icon_512x512.png │ │ └── icon_512x512@2x.png │ ├── icon-weekly.iconset │ │ ├── icon_128x128.png │ │ ├── icon_128x128@2x.png │ │ ├── icon_16x16.png │ │ ├── icon_16x16@2x.png │ │ ├── icon_256x256.png │ │ ├── icon_256x256@2x.png │ │ ├── icon_32x32.png │ │ ├── icon_32x32@2x.png │ │ ├── icon_512x512.png │ │ └── icon_512x512@2x.png │ └── icon-yearly.iconset │ │ ├── icon_128x128.png │ │ ├── icon_128x128@2x.png │ │ ├── icon_16x16.png │ │ ├── icon_16x16@2x.png │ │ ├── icon_256x256.png │ │ ├── icon_256x256@2x.png │ │ ├── icon_32x32.png │ │ ├── icon_32x32@2x.png │ │ ├── icon_512x512.png │ │ └── icon_512x512@2x.png └── ps-export │ ├── ___SOURCE.png │ ├── icon-code-bit-1024.png │ ├── icon-code-bit-128.png │ ├── icon-code-bit-16.png │ ├── icon-code-bit-256.png │ ├── icon-code-bit-32.png │ ├── icon-code-bit-64.png │ ├── icon-create-1024.png │ ├── icon-create-128.png │ ├── icon-create-16.png │ ├── icon-create-256.png │ ├── icon-create-32.png │ ├── icon-create-64.png │ ├── icon-daily-1024.png │ ├── icon-daily-128.png │ ├── icon-daily-16.png │ ├── icon-daily-256.png │ ├── icon-daily-32.png │ ├── icon-daily-64.png │ ├── icon-folder-1024.png │ ├── icon-folder-128.png │ ├── icon-folder-16.png │ ├── icon-folder-256.png │ ├── icon-folder-32.png │ ├── icon-folder-64.png │ ├── icon-hyperlink-1024.png │ ├── icon-hyperlink-128.png │ ├── icon-hyperlink-16.png │ ├── icon-hyperlink-256.png │ ├── icon-hyperlink-32.png │ ├── icon-hyperlink-64.png │ ├── icon-monthly-1024.png │ ├── icon-monthly-128.png │ ├── icon-monthly-16.png │ ├── icon-monthly-256.png │ ├── icon-monthly-32.png │ ├── icon-monthly-64.png │ ├── icon-note-1024.png │ ├── icon-note-128.png │ ├── icon-note-16.png │ ├── icon-note-256.png │ ├── icon-note-32.png │ ├── icon-note-64.png │ ├── icon-quarterly-1024.png │ ├── icon-quarterly-128.png │ ├── icon-quarterly-16.png │ ├── icon-quarterly-256.png │ ├── icon-quarterly-32.png │ ├── icon-quarterly-64.png │ ├── icon-weekly-1024.png │ ├── icon-weekly-128.png │ ├── icon-weekly-16.png │ ├── icon-weekly-256.png │ ├── icon-weekly-32.png │ ├── icon-weekly-64.png │ ├── icon-yearly-1024.png │ ├── icon-yearly-128.png │ ├── icon-yearly-16.png │ ├── icon-yearly-256.png │ ├── icon-yearly-32.png │ └── icon-yearly-64.png ├── lib ├── about.dart ├── alfred.dart ├── code_bit.dart ├── config.dart ├── date_parser.dart ├── date_utils.dart ├── dbs.dart ├── folder.dart ├── hyperlink.dart ├── int_padding.dart ├── note.dart ├── note_match.dart ├── note_type.dart ├── noteplan.dart ├── refresh.dart └── strings.dart ├── pubspec.lock ├── pubspec.yaml ├── r.sh ├── readme.md ├── social.png ├── test ├── date_parser_test.dart ├── date_utils_test.dart ├── fake-run.sh ├── note_test.dart ├── strings_test.dart ├── test.sh ├── workflow-date.sh ├── workflow-search-all.sh ├── workflow-search-code-bits.sh ├── workflow-search-hyperlinks.sh └── workflow-search-notes.sh └── workflow ├── icon.png ├── icons ├── icon-code-bit.icns ├── icon-create.icns ├── icon-daily.icns ├── icon-folder.icns ├── icon-hyperlink.icns ├── icon-monthly.icns ├── icon-note.icns ├── icon-quarterly.icns ├── icon-weekly.icns └── icon-yearly.icns └── info.plist /.editorconfig: -------------------------------------------------------------------------------- 1 | [*.dart] 2 | indent_style = tab 3 | indent_size = 4 4 | trim_trailing_whitespace = true -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Build Dart binaries & package Alfred Workflow 2 | 3 | on: 4 | workflow_dispatch: 5 | 6 | jobs: 7 | build: 8 | runs-on: macos-13 9 | 10 | steps: 11 | - name: Show the architecture 12 | run: uname -m 13 | 14 | - uses: actions/checkout@v3 15 | - uses: dart-lang/setup-dart@v1.3 16 | 17 | - name: Install dependencies 18 | run: dart pub get 19 | 20 | - name: Compile the app 21 | run: ./r.sh build 22 | 23 | - name: Capture the artifact name 24 | run: | 25 | artifact_name=`ls *.alfredworkflow | tr -d '\n'` 26 | echo "artifact_name=$artifact_name" >> $GITHUB_ENV 27 | 28 | - name: Upload Artifacts 29 | uses: actions/upload-artifact@v3 30 | with: 31 | name: ${{ env.artifact_name }} 32 | path: ${{ env.artifact_name }} -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # hihihi 2 | .DS_Store 3 | 4 | # Files and directories created by pub. 5 | .dart_tool/ 6 | .packages 7 | 8 | # Backup 9 | info.plist.bak 10 | /plist.txt 11 | 12 | # Workflow my & build data 13 | workflow/noteplan-* 14 | workflow/prefs.plist 15 | workflow/database.sqlite* 16 | 17 | # ignore database 18 | database.sqlite3 19 | 20 | # DIST 21 | workflow/LICENSES 22 | /alfred-noteplan* -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "name": "alfred-noteplan", 9 | "request": "launch", 10 | "type": "dart", 11 | "program": "bin/noteplan.dart", 12 | "args": ["search", "adam kiss"], 13 | "env": { 14 | "user_np_root": "/Users/adam/Library/Containers/co.noteplan.NotePlan-setapp/Data/Library/Application Support/co.noteplan.NotePlan-setapp" 15 | } 16 | } 17 | ] 18 | } -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | // See https://go.microsoft.com/fwlink/?LinkId=733558 3 | // for the documentation about the tasks.json format 4 | "version": "2.0.0", 5 | "tasks": [ 6 | { 7 | "label": "Open the database", 8 | "type": "shell", 9 | "command": "open ./workflow/database.sqlite3", 10 | "problemMatcher": [] 11 | }, 12 | { 13 | "label": "Open the Noteplan database", 14 | "type": "shell", 15 | "command": "open /Users/adam/Library/Containers/co.noteplan.NotePlan-setapp/Data/Library/Application\\ Support/co.noteplan.NotePlan-setapp/Caches/sync-cache.db", 16 | "problemMatcher": [] 17 | }, 18 | { 19 | "label": "Build the executable", 20 | "type": "shell", 21 | "command": "./r.sh build:dart", 22 | "problemMatcher": [], 23 | "group": { 24 | "kind": "build", 25 | "isDefault": true 26 | } 27 | }, 28 | { 29 | "label": "Run the refresh script with dart", 30 | "type": "shell", 31 | "command": "r test", 32 | "group": { 33 | "kind": "test" 34 | }, 35 | "problemMatcher": [], 36 | }, 37 | { 38 | "label": "Run actual dart tests", 39 | "type": "shell", 40 | "command": "dart test", 41 | "group": { 42 | "kind": "test", 43 | "isDefault": true 44 | }, 45 | "problemMatcher": [], 46 | "presentation": { 47 | "echo": true, 48 | "reveal": "always", 49 | "focus": false, 50 | "panel": "shared", 51 | "showReuseMessage": true, 52 | "clear": true 53 | } 54 | } 55 | ] 56 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Alfred Noteplan FTS workflow v2 2 | Copyright (c) 2023 Adam Kiss 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all 12 | copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | SOFTWARE. -------------------------------------------------------------------------------- /analysis_options.yaml: -------------------------------------------------------------------------------- 1 | # This file configures the static analysis results for your project (errors, 2 | # warnings, and lints). 3 | # 4 | # This enables the 'recommended' set of lints from `package:lints`. 5 | # This set helps identify many issues that may lead to problems when running 6 | # or consuming Dart code, and enforces writing Dart using a single, idiomatic 7 | # style and format. 8 | # 9 | # If you want a smaller set of lints you can change this to specify 10 | # 'package:lints/core.yaml'. These are just the most critical lints 11 | # (the recommended set includes the core lints). 12 | # The core lints are also what is used by pub.dev for scoring packages. 13 | 14 | include: package:lints/recommended.yaml 15 | 16 | # Uncomment the following section to specify additional rules. 17 | 18 | linter: 19 | rules: 20 | non_constant_identifier_names: false # I want to use under_lined_functions 21 | unnecessary_brace_in_string_interps: false # Yeah, `${}` is for 22 | 23 | 24 | analyzer: 25 | exclude: 26 | - lib/day__scaffold.dart 27 | 28 | # For more information about the core and recommended set of lints, see 29 | # https://dart.dev/go/core-lints 30 | 31 | # For additional information about configuring this file, see 32 | # https://dart.dev/guides/language/analysis-options -------------------------------------------------------------------------------- /bin-cache/noteplan-arm64: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adamkiss/alfred-noteplan/c8689c4779216c31628b797777b863e302ba4500/bin-cache/noteplan-arm64 -------------------------------------------------------------------------------- /bin/noteplan.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | import 'package:alfred_noteplan/about.dart'; 4 | import 'package:alfred_noteplan/alfred.dart'; 5 | import 'package:alfred_noteplan/config.dart'; 6 | import 'package:alfred_noteplan/date_parser.dart'; 7 | import 'package:alfred_noteplan/dbs.dart'; 8 | import 'package:alfred_noteplan/note_match.dart'; 9 | import 'package:alfred_noteplan/noteplan.dart'; 10 | import 'package:alfred_noteplan/refresh.dart'; 11 | import 'package:alfred_noteplan/strings.dart'; 12 | 13 | bool _last_update_more_than(int last_update, {int compare = 10}) { 14 | return DateTime.now().millisecondsSinceEpoch > (last_update + compare); 15 | } 16 | 17 | void main (List arguments) { 18 | final int run_start = Config.ts(); 19 | Config.init(); 20 | 21 | if (arguments.isEmpty) { 22 | Config.error(str_error_missing_command); 23 | } 24 | 25 | final String command = arguments.first; 26 | final String query = arguments.sublist(1).join(' ').trim(); 27 | 28 | final db = Dbs(); 29 | 30 | // Refresh & Exit 31 | if (command == 'refresh') { 32 | final int update_count = refresh(db, force: query == 'force'); 33 | print(alf_to_results([ 34 | alf_item( 35 | "${query == 'force' ? 'Force updated' : 'Updated'} ${update_count} items in ${Config.ts() - run_start}ms", 36 | str_update_subtitle, 37 | arg: '🎉', 38 | variables: {'action': 'close'} 39 | ) 40 | ])); 41 | exit(0); 42 | } 43 | 44 | // About 45 | if (command == 'debug') { 46 | final about = About(); 47 | print(about.to_alfred()); 48 | 49 | db.dispose(); 50 | exit(0); 51 | } 52 | 53 | // From now on, we totally need query, so die if it's empty 54 | if (query.isEmpty) { 55 | Config.error(str_error_missing_args); 56 | } 57 | 58 | // Create new note 59 | if (command == 'create') { 60 | print(alf_to_results( 61 | db.cache_list_folders(query) 62 | .map((e) => e.to_alfred()) 63 | .toList(growable: false) 64 | )); 65 | 66 | db.dispose(); 67 | exit(0); 68 | } 69 | 70 | final int last_update = db.get_last_update(); 71 | if (_last_update_more_than(last_update)) { refresh(db); } 72 | 73 | // Bookmarks 74 | if (command == 'hyperlinks') { 75 | print(alf_to_results(db.search_hyperlinks(query))); 76 | db.dispose(); 77 | exit(0); 78 | } 79 | 80 | // Snippets 81 | if (command == 'code_bits') { 82 | print(alf_to_results(db.search_code_bits(query))); 83 | db.dispose(); 84 | exit(0); 85 | } 86 | 87 | // Search (notes, hyperlinks and code bits) 88 | if (command == 'all') { 89 | print(alf_to_results( 90 | db.search_all(query) 91 | ..add(alf_create_item(query)) 92 | )); 93 | db.dispose(); 94 | exit(0); 95 | } 96 | 97 | // Date parsing 98 | if (command == 'date') { 99 | try { 100 | final DateParser parsed = DateParser(query); 101 | final (String, String) np = parsed.toNoteplan(); 102 | 103 | alf_exit([ 104 | alf_item( 105 | np.$1, 106 | 'Open or create a ${parsed.type!.value} note named "${np.$2}.md"', 107 | arg: Noteplan.openCalendarUrl(np.$2), 108 | valid: true, 109 | variables: {'action':'open'}, 110 | mods: { 111 | 'cmd': { 112 | 'subtitle': str_fts_result_arg_cmd_subtitle, 113 | 'arg': Noteplan.openCalendarUrl(np.$2, sameWindow: false) 114 | } 115 | } 116 | ) 117 | ]); 118 | } catch (e) { 119 | alf_exit([ 120 | alf_item('…', 'Waiting for a valid query', valid: false) 121 | ]); 122 | } 123 | } 124 | 125 | // Finally: Full-text search 126 | List found = db.search_notes(query); 127 | print(alf_to_results( 128 | found 129 | .map((e) => e.to_alfred_result()) 130 | .toList() 131 | ..add(alf_create_item(query)) 132 | )); 133 | 134 | // DISPOSE 135 | db.dispose(); 136 | } -------------------------------------------------------------------------------- /icons/iconsets/icon-code-bit.iconset/icon_128x128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adamkiss/alfred-noteplan/c8689c4779216c31628b797777b863e302ba4500/icons/iconsets/icon-code-bit.iconset/icon_128x128.png -------------------------------------------------------------------------------- /icons/iconsets/icon-code-bit.iconset/icon_128x128@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adamkiss/alfred-noteplan/c8689c4779216c31628b797777b863e302ba4500/icons/iconsets/icon-code-bit.iconset/icon_128x128@2x.png -------------------------------------------------------------------------------- /icons/iconsets/icon-code-bit.iconset/icon_16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adamkiss/alfred-noteplan/c8689c4779216c31628b797777b863e302ba4500/icons/iconsets/icon-code-bit.iconset/icon_16x16.png -------------------------------------------------------------------------------- /icons/iconsets/icon-code-bit.iconset/icon_16x16@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adamkiss/alfred-noteplan/c8689c4779216c31628b797777b863e302ba4500/icons/iconsets/icon-code-bit.iconset/icon_16x16@2x.png -------------------------------------------------------------------------------- /icons/iconsets/icon-code-bit.iconset/icon_256x256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adamkiss/alfred-noteplan/c8689c4779216c31628b797777b863e302ba4500/icons/iconsets/icon-code-bit.iconset/icon_256x256.png -------------------------------------------------------------------------------- /icons/iconsets/icon-code-bit.iconset/icon_256x256@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adamkiss/alfred-noteplan/c8689c4779216c31628b797777b863e302ba4500/icons/iconsets/icon-code-bit.iconset/icon_256x256@2x.png -------------------------------------------------------------------------------- /icons/iconsets/icon-code-bit.iconset/icon_32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adamkiss/alfred-noteplan/c8689c4779216c31628b797777b863e302ba4500/icons/iconsets/icon-code-bit.iconset/icon_32x32.png -------------------------------------------------------------------------------- /icons/iconsets/icon-code-bit.iconset/icon_32x32@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adamkiss/alfred-noteplan/c8689c4779216c31628b797777b863e302ba4500/icons/iconsets/icon-code-bit.iconset/icon_32x32@2x.png -------------------------------------------------------------------------------- /icons/iconsets/icon-code-bit.iconset/icon_512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adamkiss/alfred-noteplan/c8689c4779216c31628b797777b863e302ba4500/icons/iconsets/icon-code-bit.iconset/icon_512x512.png -------------------------------------------------------------------------------- /icons/iconsets/icon-code-bit.iconset/icon_512x512@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adamkiss/alfred-noteplan/c8689c4779216c31628b797777b863e302ba4500/icons/iconsets/icon-code-bit.iconset/icon_512x512@2x.png -------------------------------------------------------------------------------- /icons/iconsets/icon-create.iconset/icon_128x128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adamkiss/alfred-noteplan/c8689c4779216c31628b797777b863e302ba4500/icons/iconsets/icon-create.iconset/icon_128x128.png -------------------------------------------------------------------------------- /icons/iconsets/icon-create.iconset/icon_128x128@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adamkiss/alfred-noteplan/c8689c4779216c31628b797777b863e302ba4500/icons/iconsets/icon-create.iconset/icon_128x128@2x.png -------------------------------------------------------------------------------- /icons/iconsets/icon-create.iconset/icon_16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adamkiss/alfred-noteplan/c8689c4779216c31628b797777b863e302ba4500/icons/iconsets/icon-create.iconset/icon_16x16.png -------------------------------------------------------------------------------- /icons/iconsets/icon-create.iconset/icon_16x16@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adamkiss/alfred-noteplan/c8689c4779216c31628b797777b863e302ba4500/icons/iconsets/icon-create.iconset/icon_16x16@2x.png -------------------------------------------------------------------------------- /icons/iconsets/icon-create.iconset/icon_256x256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adamkiss/alfred-noteplan/c8689c4779216c31628b797777b863e302ba4500/icons/iconsets/icon-create.iconset/icon_256x256.png -------------------------------------------------------------------------------- /icons/iconsets/icon-create.iconset/icon_256x256@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adamkiss/alfred-noteplan/c8689c4779216c31628b797777b863e302ba4500/icons/iconsets/icon-create.iconset/icon_256x256@2x.png -------------------------------------------------------------------------------- /icons/iconsets/icon-create.iconset/icon_32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adamkiss/alfred-noteplan/c8689c4779216c31628b797777b863e302ba4500/icons/iconsets/icon-create.iconset/icon_32x32.png -------------------------------------------------------------------------------- /icons/iconsets/icon-create.iconset/icon_32x32@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adamkiss/alfred-noteplan/c8689c4779216c31628b797777b863e302ba4500/icons/iconsets/icon-create.iconset/icon_32x32@2x.png -------------------------------------------------------------------------------- /icons/iconsets/icon-create.iconset/icon_512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adamkiss/alfred-noteplan/c8689c4779216c31628b797777b863e302ba4500/icons/iconsets/icon-create.iconset/icon_512x512.png -------------------------------------------------------------------------------- /icons/iconsets/icon-create.iconset/icon_512x512@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adamkiss/alfred-noteplan/c8689c4779216c31628b797777b863e302ba4500/icons/iconsets/icon-create.iconset/icon_512x512@2x.png -------------------------------------------------------------------------------- /icons/iconsets/icon-daily.iconset/icon_128x128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adamkiss/alfred-noteplan/c8689c4779216c31628b797777b863e302ba4500/icons/iconsets/icon-daily.iconset/icon_128x128.png -------------------------------------------------------------------------------- /icons/iconsets/icon-daily.iconset/icon_128x128@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adamkiss/alfred-noteplan/c8689c4779216c31628b797777b863e302ba4500/icons/iconsets/icon-daily.iconset/icon_128x128@2x.png -------------------------------------------------------------------------------- /icons/iconsets/icon-daily.iconset/icon_16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adamkiss/alfred-noteplan/c8689c4779216c31628b797777b863e302ba4500/icons/iconsets/icon-daily.iconset/icon_16x16.png -------------------------------------------------------------------------------- /icons/iconsets/icon-daily.iconset/icon_16x16@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adamkiss/alfred-noteplan/c8689c4779216c31628b797777b863e302ba4500/icons/iconsets/icon-daily.iconset/icon_16x16@2x.png -------------------------------------------------------------------------------- /icons/iconsets/icon-daily.iconset/icon_256x256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adamkiss/alfred-noteplan/c8689c4779216c31628b797777b863e302ba4500/icons/iconsets/icon-daily.iconset/icon_256x256.png -------------------------------------------------------------------------------- /icons/iconsets/icon-daily.iconset/icon_256x256@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adamkiss/alfred-noteplan/c8689c4779216c31628b797777b863e302ba4500/icons/iconsets/icon-daily.iconset/icon_256x256@2x.png -------------------------------------------------------------------------------- /icons/iconsets/icon-daily.iconset/icon_32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adamkiss/alfred-noteplan/c8689c4779216c31628b797777b863e302ba4500/icons/iconsets/icon-daily.iconset/icon_32x32.png -------------------------------------------------------------------------------- /icons/iconsets/icon-daily.iconset/icon_32x32@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adamkiss/alfred-noteplan/c8689c4779216c31628b797777b863e302ba4500/icons/iconsets/icon-daily.iconset/icon_32x32@2x.png -------------------------------------------------------------------------------- /icons/iconsets/icon-daily.iconset/icon_512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adamkiss/alfred-noteplan/c8689c4779216c31628b797777b863e302ba4500/icons/iconsets/icon-daily.iconset/icon_512x512.png -------------------------------------------------------------------------------- /icons/iconsets/icon-daily.iconset/icon_512x512@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adamkiss/alfred-noteplan/c8689c4779216c31628b797777b863e302ba4500/icons/iconsets/icon-daily.iconset/icon_512x512@2x.png -------------------------------------------------------------------------------- /icons/iconsets/icon-folder.iconset/icon_128x128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adamkiss/alfred-noteplan/c8689c4779216c31628b797777b863e302ba4500/icons/iconsets/icon-folder.iconset/icon_128x128.png -------------------------------------------------------------------------------- /icons/iconsets/icon-folder.iconset/icon_128x128@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adamkiss/alfred-noteplan/c8689c4779216c31628b797777b863e302ba4500/icons/iconsets/icon-folder.iconset/icon_128x128@2x.png -------------------------------------------------------------------------------- /icons/iconsets/icon-folder.iconset/icon_16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adamkiss/alfred-noteplan/c8689c4779216c31628b797777b863e302ba4500/icons/iconsets/icon-folder.iconset/icon_16x16.png -------------------------------------------------------------------------------- /icons/iconsets/icon-folder.iconset/icon_16x16@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adamkiss/alfred-noteplan/c8689c4779216c31628b797777b863e302ba4500/icons/iconsets/icon-folder.iconset/icon_16x16@2x.png -------------------------------------------------------------------------------- /icons/iconsets/icon-folder.iconset/icon_256x256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adamkiss/alfred-noteplan/c8689c4779216c31628b797777b863e302ba4500/icons/iconsets/icon-folder.iconset/icon_256x256.png -------------------------------------------------------------------------------- /icons/iconsets/icon-folder.iconset/icon_256x256@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adamkiss/alfred-noteplan/c8689c4779216c31628b797777b863e302ba4500/icons/iconsets/icon-folder.iconset/icon_256x256@2x.png -------------------------------------------------------------------------------- /icons/iconsets/icon-folder.iconset/icon_32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adamkiss/alfred-noteplan/c8689c4779216c31628b797777b863e302ba4500/icons/iconsets/icon-folder.iconset/icon_32x32.png -------------------------------------------------------------------------------- /icons/iconsets/icon-folder.iconset/icon_32x32@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adamkiss/alfred-noteplan/c8689c4779216c31628b797777b863e302ba4500/icons/iconsets/icon-folder.iconset/icon_32x32@2x.png -------------------------------------------------------------------------------- /icons/iconsets/icon-folder.iconset/icon_512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adamkiss/alfred-noteplan/c8689c4779216c31628b797777b863e302ba4500/icons/iconsets/icon-folder.iconset/icon_512x512.png -------------------------------------------------------------------------------- /icons/iconsets/icon-folder.iconset/icon_512x512@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adamkiss/alfred-noteplan/c8689c4779216c31628b797777b863e302ba4500/icons/iconsets/icon-folder.iconset/icon_512x512@2x.png -------------------------------------------------------------------------------- /icons/iconsets/icon-hyperlink.iconset/icon_128x128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adamkiss/alfred-noteplan/c8689c4779216c31628b797777b863e302ba4500/icons/iconsets/icon-hyperlink.iconset/icon_128x128.png -------------------------------------------------------------------------------- /icons/iconsets/icon-hyperlink.iconset/icon_128x128@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adamkiss/alfred-noteplan/c8689c4779216c31628b797777b863e302ba4500/icons/iconsets/icon-hyperlink.iconset/icon_128x128@2x.png -------------------------------------------------------------------------------- /icons/iconsets/icon-hyperlink.iconset/icon_16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adamkiss/alfred-noteplan/c8689c4779216c31628b797777b863e302ba4500/icons/iconsets/icon-hyperlink.iconset/icon_16x16.png -------------------------------------------------------------------------------- /icons/iconsets/icon-hyperlink.iconset/icon_16x16@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adamkiss/alfred-noteplan/c8689c4779216c31628b797777b863e302ba4500/icons/iconsets/icon-hyperlink.iconset/icon_16x16@2x.png -------------------------------------------------------------------------------- /icons/iconsets/icon-hyperlink.iconset/icon_256x256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adamkiss/alfred-noteplan/c8689c4779216c31628b797777b863e302ba4500/icons/iconsets/icon-hyperlink.iconset/icon_256x256.png -------------------------------------------------------------------------------- /icons/iconsets/icon-hyperlink.iconset/icon_256x256@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adamkiss/alfred-noteplan/c8689c4779216c31628b797777b863e302ba4500/icons/iconsets/icon-hyperlink.iconset/icon_256x256@2x.png -------------------------------------------------------------------------------- /icons/iconsets/icon-hyperlink.iconset/icon_32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adamkiss/alfred-noteplan/c8689c4779216c31628b797777b863e302ba4500/icons/iconsets/icon-hyperlink.iconset/icon_32x32.png -------------------------------------------------------------------------------- /icons/iconsets/icon-hyperlink.iconset/icon_32x32@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adamkiss/alfred-noteplan/c8689c4779216c31628b797777b863e302ba4500/icons/iconsets/icon-hyperlink.iconset/icon_32x32@2x.png -------------------------------------------------------------------------------- /icons/iconsets/icon-hyperlink.iconset/icon_512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adamkiss/alfred-noteplan/c8689c4779216c31628b797777b863e302ba4500/icons/iconsets/icon-hyperlink.iconset/icon_512x512.png -------------------------------------------------------------------------------- /icons/iconsets/icon-hyperlink.iconset/icon_512x512@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adamkiss/alfred-noteplan/c8689c4779216c31628b797777b863e302ba4500/icons/iconsets/icon-hyperlink.iconset/icon_512x512@2x.png -------------------------------------------------------------------------------- /icons/iconsets/icon-monthly.iconset/icon_128x128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adamkiss/alfred-noteplan/c8689c4779216c31628b797777b863e302ba4500/icons/iconsets/icon-monthly.iconset/icon_128x128.png -------------------------------------------------------------------------------- /icons/iconsets/icon-monthly.iconset/icon_128x128@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adamkiss/alfred-noteplan/c8689c4779216c31628b797777b863e302ba4500/icons/iconsets/icon-monthly.iconset/icon_128x128@2x.png -------------------------------------------------------------------------------- /icons/iconsets/icon-monthly.iconset/icon_16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adamkiss/alfred-noteplan/c8689c4779216c31628b797777b863e302ba4500/icons/iconsets/icon-monthly.iconset/icon_16x16.png -------------------------------------------------------------------------------- /icons/iconsets/icon-monthly.iconset/icon_16x16@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adamkiss/alfred-noteplan/c8689c4779216c31628b797777b863e302ba4500/icons/iconsets/icon-monthly.iconset/icon_16x16@2x.png -------------------------------------------------------------------------------- /icons/iconsets/icon-monthly.iconset/icon_256x256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adamkiss/alfred-noteplan/c8689c4779216c31628b797777b863e302ba4500/icons/iconsets/icon-monthly.iconset/icon_256x256.png -------------------------------------------------------------------------------- /icons/iconsets/icon-monthly.iconset/icon_256x256@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adamkiss/alfred-noteplan/c8689c4779216c31628b797777b863e302ba4500/icons/iconsets/icon-monthly.iconset/icon_256x256@2x.png -------------------------------------------------------------------------------- /icons/iconsets/icon-monthly.iconset/icon_32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adamkiss/alfred-noteplan/c8689c4779216c31628b797777b863e302ba4500/icons/iconsets/icon-monthly.iconset/icon_32x32.png -------------------------------------------------------------------------------- /icons/iconsets/icon-monthly.iconset/icon_32x32@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adamkiss/alfred-noteplan/c8689c4779216c31628b797777b863e302ba4500/icons/iconsets/icon-monthly.iconset/icon_32x32@2x.png -------------------------------------------------------------------------------- /icons/iconsets/icon-monthly.iconset/icon_512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adamkiss/alfred-noteplan/c8689c4779216c31628b797777b863e302ba4500/icons/iconsets/icon-monthly.iconset/icon_512x512.png -------------------------------------------------------------------------------- /icons/iconsets/icon-monthly.iconset/icon_512x512@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adamkiss/alfred-noteplan/c8689c4779216c31628b797777b863e302ba4500/icons/iconsets/icon-monthly.iconset/icon_512x512@2x.png -------------------------------------------------------------------------------- /icons/iconsets/icon-note.iconset/icon_128x128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adamkiss/alfred-noteplan/c8689c4779216c31628b797777b863e302ba4500/icons/iconsets/icon-note.iconset/icon_128x128.png -------------------------------------------------------------------------------- /icons/iconsets/icon-note.iconset/icon_128x128@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adamkiss/alfred-noteplan/c8689c4779216c31628b797777b863e302ba4500/icons/iconsets/icon-note.iconset/icon_128x128@2x.png -------------------------------------------------------------------------------- /icons/iconsets/icon-note.iconset/icon_16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adamkiss/alfred-noteplan/c8689c4779216c31628b797777b863e302ba4500/icons/iconsets/icon-note.iconset/icon_16x16.png -------------------------------------------------------------------------------- /icons/iconsets/icon-note.iconset/icon_16x16@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adamkiss/alfred-noteplan/c8689c4779216c31628b797777b863e302ba4500/icons/iconsets/icon-note.iconset/icon_16x16@2x.png -------------------------------------------------------------------------------- /icons/iconsets/icon-note.iconset/icon_256x256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adamkiss/alfred-noteplan/c8689c4779216c31628b797777b863e302ba4500/icons/iconsets/icon-note.iconset/icon_256x256.png -------------------------------------------------------------------------------- /icons/iconsets/icon-note.iconset/icon_256x256@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adamkiss/alfred-noteplan/c8689c4779216c31628b797777b863e302ba4500/icons/iconsets/icon-note.iconset/icon_256x256@2x.png -------------------------------------------------------------------------------- /icons/iconsets/icon-note.iconset/icon_32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adamkiss/alfred-noteplan/c8689c4779216c31628b797777b863e302ba4500/icons/iconsets/icon-note.iconset/icon_32x32.png -------------------------------------------------------------------------------- /icons/iconsets/icon-note.iconset/icon_32x32@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adamkiss/alfred-noteplan/c8689c4779216c31628b797777b863e302ba4500/icons/iconsets/icon-note.iconset/icon_32x32@2x.png -------------------------------------------------------------------------------- /icons/iconsets/icon-note.iconset/icon_512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adamkiss/alfred-noteplan/c8689c4779216c31628b797777b863e302ba4500/icons/iconsets/icon-note.iconset/icon_512x512.png -------------------------------------------------------------------------------- /icons/iconsets/icon-note.iconset/icon_512x512@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adamkiss/alfred-noteplan/c8689c4779216c31628b797777b863e302ba4500/icons/iconsets/icon-note.iconset/icon_512x512@2x.png -------------------------------------------------------------------------------- /icons/iconsets/icon-quarterly.iconset/icon_128x128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adamkiss/alfred-noteplan/c8689c4779216c31628b797777b863e302ba4500/icons/iconsets/icon-quarterly.iconset/icon_128x128.png -------------------------------------------------------------------------------- /icons/iconsets/icon-quarterly.iconset/icon_128x128@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adamkiss/alfred-noteplan/c8689c4779216c31628b797777b863e302ba4500/icons/iconsets/icon-quarterly.iconset/icon_128x128@2x.png -------------------------------------------------------------------------------- /icons/iconsets/icon-quarterly.iconset/icon_16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adamkiss/alfred-noteplan/c8689c4779216c31628b797777b863e302ba4500/icons/iconsets/icon-quarterly.iconset/icon_16x16.png -------------------------------------------------------------------------------- /icons/iconsets/icon-quarterly.iconset/icon_16x16@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adamkiss/alfred-noteplan/c8689c4779216c31628b797777b863e302ba4500/icons/iconsets/icon-quarterly.iconset/icon_16x16@2x.png -------------------------------------------------------------------------------- /icons/iconsets/icon-quarterly.iconset/icon_256x256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adamkiss/alfred-noteplan/c8689c4779216c31628b797777b863e302ba4500/icons/iconsets/icon-quarterly.iconset/icon_256x256.png -------------------------------------------------------------------------------- /icons/iconsets/icon-quarterly.iconset/icon_256x256@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adamkiss/alfred-noteplan/c8689c4779216c31628b797777b863e302ba4500/icons/iconsets/icon-quarterly.iconset/icon_256x256@2x.png -------------------------------------------------------------------------------- /icons/iconsets/icon-quarterly.iconset/icon_32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adamkiss/alfred-noteplan/c8689c4779216c31628b797777b863e302ba4500/icons/iconsets/icon-quarterly.iconset/icon_32x32.png -------------------------------------------------------------------------------- /icons/iconsets/icon-quarterly.iconset/icon_32x32@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adamkiss/alfred-noteplan/c8689c4779216c31628b797777b863e302ba4500/icons/iconsets/icon-quarterly.iconset/icon_32x32@2x.png -------------------------------------------------------------------------------- /icons/iconsets/icon-quarterly.iconset/icon_512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adamkiss/alfred-noteplan/c8689c4779216c31628b797777b863e302ba4500/icons/iconsets/icon-quarterly.iconset/icon_512x512.png -------------------------------------------------------------------------------- /icons/iconsets/icon-quarterly.iconset/icon_512x512@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adamkiss/alfred-noteplan/c8689c4779216c31628b797777b863e302ba4500/icons/iconsets/icon-quarterly.iconset/icon_512x512@2x.png -------------------------------------------------------------------------------- /icons/iconsets/icon-weekly.iconset/icon_128x128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adamkiss/alfred-noteplan/c8689c4779216c31628b797777b863e302ba4500/icons/iconsets/icon-weekly.iconset/icon_128x128.png -------------------------------------------------------------------------------- /icons/iconsets/icon-weekly.iconset/icon_128x128@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adamkiss/alfred-noteplan/c8689c4779216c31628b797777b863e302ba4500/icons/iconsets/icon-weekly.iconset/icon_128x128@2x.png -------------------------------------------------------------------------------- /icons/iconsets/icon-weekly.iconset/icon_16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adamkiss/alfred-noteplan/c8689c4779216c31628b797777b863e302ba4500/icons/iconsets/icon-weekly.iconset/icon_16x16.png -------------------------------------------------------------------------------- /icons/iconsets/icon-weekly.iconset/icon_16x16@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adamkiss/alfred-noteplan/c8689c4779216c31628b797777b863e302ba4500/icons/iconsets/icon-weekly.iconset/icon_16x16@2x.png -------------------------------------------------------------------------------- /icons/iconsets/icon-weekly.iconset/icon_256x256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adamkiss/alfred-noteplan/c8689c4779216c31628b797777b863e302ba4500/icons/iconsets/icon-weekly.iconset/icon_256x256.png -------------------------------------------------------------------------------- /icons/iconsets/icon-weekly.iconset/icon_256x256@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adamkiss/alfred-noteplan/c8689c4779216c31628b797777b863e302ba4500/icons/iconsets/icon-weekly.iconset/icon_256x256@2x.png -------------------------------------------------------------------------------- /icons/iconsets/icon-weekly.iconset/icon_32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adamkiss/alfred-noteplan/c8689c4779216c31628b797777b863e302ba4500/icons/iconsets/icon-weekly.iconset/icon_32x32.png -------------------------------------------------------------------------------- /icons/iconsets/icon-weekly.iconset/icon_32x32@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adamkiss/alfred-noteplan/c8689c4779216c31628b797777b863e302ba4500/icons/iconsets/icon-weekly.iconset/icon_32x32@2x.png -------------------------------------------------------------------------------- /icons/iconsets/icon-weekly.iconset/icon_512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adamkiss/alfred-noteplan/c8689c4779216c31628b797777b863e302ba4500/icons/iconsets/icon-weekly.iconset/icon_512x512.png -------------------------------------------------------------------------------- /icons/iconsets/icon-weekly.iconset/icon_512x512@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adamkiss/alfred-noteplan/c8689c4779216c31628b797777b863e302ba4500/icons/iconsets/icon-weekly.iconset/icon_512x512@2x.png -------------------------------------------------------------------------------- /icons/iconsets/icon-yearly.iconset/icon_128x128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adamkiss/alfred-noteplan/c8689c4779216c31628b797777b863e302ba4500/icons/iconsets/icon-yearly.iconset/icon_128x128.png -------------------------------------------------------------------------------- /icons/iconsets/icon-yearly.iconset/icon_128x128@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adamkiss/alfred-noteplan/c8689c4779216c31628b797777b863e302ba4500/icons/iconsets/icon-yearly.iconset/icon_128x128@2x.png -------------------------------------------------------------------------------- /icons/iconsets/icon-yearly.iconset/icon_16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adamkiss/alfred-noteplan/c8689c4779216c31628b797777b863e302ba4500/icons/iconsets/icon-yearly.iconset/icon_16x16.png -------------------------------------------------------------------------------- /icons/iconsets/icon-yearly.iconset/icon_16x16@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adamkiss/alfred-noteplan/c8689c4779216c31628b797777b863e302ba4500/icons/iconsets/icon-yearly.iconset/icon_16x16@2x.png -------------------------------------------------------------------------------- /icons/iconsets/icon-yearly.iconset/icon_256x256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adamkiss/alfred-noteplan/c8689c4779216c31628b797777b863e302ba4500/icons/iconsets/icon-yearly.iconset/icon_256x256.png -------------------------------------------------------------------------------- /icons/iconsets/icon-yearly.iconset/icon_256x256@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adamkiss/alfred-noteplan/c8689c4779216c31628b797777b863e302ba4500/icons/iconsets/icon-yearly.iconset/icon_256x256@2x.png -------------------------------------------------------------------------------- /icons/iconsets/icon-yearly.iconset/icon_32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adamkiss/alfred-noteplan/c8689c4779216c31628b797777b863e302ba4500/icons/iconsets/icon-yearly.iconset/icon_32x32.png -------------------------------------------------------------------------------- /icons/iconsets/icon-yearly.iconset/icon_32x32@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adamkiss/alfred-noteplan/c8689c4779216c31628b797777b863e302ba4500/icons/iconsets/icon-yearly.iconset/icon_32x32@2x.png -------------------------------------------------------------------------------- /icons/iconsets/icon-yearly.iconset/icon_512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adamkiss/alfred-noteplan/c8689c4779216c31628b797777b863e302ba4500/icons/iconsets/icon-yearly.iconset/icon_512x512.png -------------------------------------------------------------------------------- /icons/iconsets/icon-yearly.iconset/icon_512x512@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adamkiss/alfred-noteplan/c8689c4779216c31628b797777b863e302ba4500/icons/iconsets/icon-yearly.iconset/icon_512x512@2x.png -------------------------------------------------------------------------------- /icons/ps-export/___SOURCE.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adamkiss/alfred-noteplan/c8689c4779216c31628b797777b863e302ba4500/icons/ps-export/___SOURCE.png -------------------------------------------------------------------------------- /icons/ps-export/icon-code-bit-1024.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adamkiss/alfred-noteplan/c8689c4779216c31628b797777b863e302ba4500/icons/ps-export/icon-code-bit-1024.png -------------------------------------------------------------------------------- /icons/ps-export/icon-code-bit-128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adamkiss/alfred-noteplan/c8689c4779216c31628b797777b863e302ba4500/icons/ps-export/icon-code-bit-128.png -------------------------------------------------------------------------------- /icons/ps-export/icon-code-bit-16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adamkiss/alfred-noteplan/c8689c4779216c31628b797777b863e302ba4500/icons/ps-export/icon-code-bit-16.png -------------------------------------------------------------------------------- /icons/ps-export/icon-code-bit-256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adamkiss/alfred-noteplan/c8689c4779216c31628b797777b863e302ba4500/icons/ps-export/icon-code-bit-256.png -------------------------------------------------------------------------------- /icons/ps-export/icon-code-bit-32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adamkiss/alfred-noteplan/c8689c4779216c31628b797777b863e302ba4500/icons/ps-export/icon-code-bit-32.png -------------------------------------------------------------------------------- /icons/ps-export/icon-code-bit-64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adamkiss/alfred-noteplan/c8689c4779216c31628b797777b863e302ba4500/icons/ps-export/icon-code-bit-64.png -------------------------------------------------------------------------------- /icons/ps-export/icon-create-1024.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adamkiss/alfred-noteplan/c8689c4779216c31628b797777b863e302ba4500/icons/ps-export/icon-create-1024.png -------------------------------------------------------------------------------- /icons/ps-export/icon-create-128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adamkiss/alfred-noteplan/c8689c4779216c31628b797777b863e302ba4500/icons/ps-export/icon-create-128.png -------------------------------------------------------------------------------- /icons/ps-export/icon-create-16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adamkiss/alfred-noteplan/c8689c4779216c31628b797777b863e302ba4500/icons/ps-export/icon-create-16.png -------------------------------------------------------------------------------- /icons/ps-export/icon-create-256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adamkiss/alfred-noteplan/c8689c4779216c31628b797777b863e302ba4500/icons/ps-export/icon-create-256.png -------------------------------------------------------------------------------- /icons/ps-export/icon-create-32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adamkiss/alfred-noteplan/c8689c4779216c31628b797777b863e302ba4500/icons/ps-export/icon-create-32.png -------------------------------------------------------------------------------- /icons/ps-export/icon-create-64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adamkiss/alfred-noteplan/c8689c4779216c31628b797777b863e302ba4500/icons/ps-export/icon-create-64.png -------------------------------------------------------------------------------- /icons/ps-export/icon-daily-1024.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adamkiss/alfred-noteplan/c8689c4779216c31628b797777b863e302ba4500/icons/ps-export/icon-daily-1024.png -------------------------------------------------------------------------------- /icons/ps-export/icon-daily-128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adamkiss/alfred-noteplan/c8689c4779216c31628b797777b863e302ba4500/icons/ps-export/icon-daily-128.png -------------------------------------------------------------------------------- /icons/ps-export/icon-daily-16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adamkiss/alfred-noteplan/c8689c4779216c31628b797777b863e302ba4500/icons/ps-export/icon-daily-16.png -------------------------------------------------------------------------------- /icons/ps-export/icon-daily-256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adamkiss/alfred-noteplan/c8689c4779216c31628b797777b863e302ba4500/icons/ps-export/icon-daily-256.png -------------------------------------------------------------------------------- /icons/ps-export/icon-daily-32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adamkiss/alfred-noteplan/c8689c4779216c31628b797777b863e302ba4500/icons/ps-export/icon-daily-32.png -------------------------------------------------------------------------------- /icons/ps-export/icon-daily-64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adamkiss/alfred-noteplan/c8689c4779216c31628b797777b863e302ba4500/icons/ps-export/icon-daily-64.png -------------------------------------------------------------------------------- /icons/ps-export/icon-folder-1024.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adamkiss/alfred-noteplan/c8689c4779216c31628b797777b863e302ba4500/icons/ps-export/icon-folder-1024.png -------------------------------------------------------------------------------- /icons/ps-export/icon-folder-128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adamkiss/alfred-noteplan/c8689c4779216c31628b797777b863e302ba4500/icons/ps-export/icon-folder-128.png -------------------------------------------------------------------------------- /icons/ps-export/icon-folder-16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adamkiss/alfred-noteplan/c8689c4779216c31628b797777b863e302ba4500/icons/ps-export/icon-folder-16.png -------------------------------------------------------------------------------- /icons/ps-export/icon-folder-256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adamkiss/alfred-noteplan/c8689c4779216c31628b797777b863e302ba4500/icons/ps-export/icon-folder-256.png -------------------------------------------------------------------------------- /icons/ps-export/icon-folder-32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adamkiss/alfred-noteplan/c8689c4779216c31628b797777b863e302ba4500/icons/ps-export/icon-folder-32.png -------------------------------------------------------------------------------- /icons/ps-export/icon-folder-64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adamkiss/alfred-noteplan/c8689c4779216c31628b797777b863e302ba4500/icons/ps-export/icon-folder-64.png -------------------------------------------------------------------------------- /icons/ps-export/icon-hyperlink-1024.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adamkiss/alfred-noteplan/c8689c4779216c31628b797777b863e302ba4500/icons/ps-export/icon-hyperlink-1024.png -------------------------------------------------------------------------------- /icons/ps-export/icon-hyperlink-128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adamkiss/alfred-noteplan/c8689c4779216c31628b797777b863e302ba4500/icons/ps-export/icon-hyperlink-128.png -------------------------------------------------------------------------------- /icons/ps-export/icon-hyperlink-16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adamkiss/alfred-noteplan/c8689c4779216c31628b797777b863e302ba4500/icons/ps-export/icon-hyperlink-16.png -------------------------------------------------------------------------------- /icons/ps-export/icon-hyperlink-256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adamkiss/alfred-noteplan/c8689c4779216c31628b797777b863e302ba4500/icons/ps-export/icon-hyperlink-256.png -------------------------------------------------------------------------------- /icons/ps-export/icon-hyperlink-32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adamkiss/alfred-noteplan/c8689c4779216c31628b797777b863e302ba4500/icons/ps-export/icon-hyperlink-32.png -------------------------------------------------------------------------------- /icons/ps-export/icon-hyperlink-64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adamkiss/alfred-noteplan/c8689c4779216c31628b797777b863e302ba4500/icons/ps-export/icon-hyperlink-64.png -------------------------------------------------------------------------------- /icons/ps-export/icon-monthly-1024.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adamkiss/alfred-noteplan/c8689c4779216c31628b797777b863e302ba4500/icons/ps-export/icon-monthly-1024.png -------------------------------------------------------------------------------- /icons/ps-export/icon-monthly-128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adamkiss/alfred-noteplan/c8689c4779216c31628b797777b863e302ba4500/icons/ps-export/icon-monthly-128.png -------------------------------------------------------------------------------- /icons/ps-export/icon-monthly-16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adamkiss/alfred-noteplan/c8689c4779216c31628b797777b863e302ba4500/icons/ps-export/icon-monthly-16.png -------------------------------------------------------------------------------- /icons/ps-export/icon-monthly-256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adamkiss/alfred-noteplan/c8689c4779216c31628b797777b863e302ba4500/icons/ps-export/icon-monthly-256.png -------------------------------------------------------------------------------- /icons/ps-export/icon-monthly-32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adamkiss/alfred-noteplan/c8689c4779216c31628b797777b863e302ba4500/icons/ps-export/icon-monthly-32.png -------------------------------------------------------------------------------- /icons/ps-export/icon-monthly-64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adamkiss/alfred-noteplan/c8689c4779216c31628b797777b863e302ba4500/icons/ps-export/icon-monthly-64.png -------------------------------------------------------------------------------- /icons/ps-export/icon-note-1024.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adamkiss/alfred-noteplan/c8689c4779216c31628b797777b863e302ba4500/icons/ps-export/icon-note-1024.png -------------------------------------------------------------------------------- /icons/ps-export/icon-note-128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adamkiss/alfred-noteplan/c8689c4779216c31628b797777b863e302ba4500/icons/ps-export/icon-note-128.png -------------------------------------------------------------------------------- /icons/ps-export/icon-note-16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adamkiss/alfred-noteplan/c8689c4779216c31628b797777b863e302ba4500/icons/ps-export/icon-note-16.png -------------------------------------------------------------------------------- /icons/ps-export/icon-note-256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adamkiss/alfred-noteplan/c8689c4779216c31628b797777b863e302ba4500/icons/ps-export/icon-note-256.png -------------------------------------------------------------------------------- /icons/ps-export/icon-note-32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adamkiss/alfred-noteplan/c8689c4779216c31628b797777b863e302ba4500/icons/ps-export/icon-note-32.png -------------------------------------------------------------------------------- /icons/ps-export/icon-note-64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adamkiss/alfred-noteplan/c8689c4779216c31628b797777b863e302ba4500/icons/ps-export/icon-note-64.png -------------------------------------------------------------------------------- /icons/ps-export/icon-quarterly-1024.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adamkiss/alfred-noteplan/c8689c4779216c31628b797777b863e302ba4500/icons/ps-export/icon-quarterly-1024.png -------------------------------------------------------------------------------- /icons/ps-export/icon-quarterly-128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adamkiss/alfred-noteplan/c8689c4779216c31628b797777b863e302ba4500/icons/ps-export/icon-quarterly-128.png -------------------------------------------------------------------------------- /icons/ps-export/icon-quarterly-16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adamkiss/alfred-noteplan/c8689c4779216c31628b797777b863e302ba4500/icons/ps-export/icon-quarterly-16.png -------------------------------------------------------------------------------- /icons/ps-export/icon-quarterly-256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adamkiss/alfred-noteplan/c8689c4779216c31628b797777b863e302ba4500/icons/ps-export/icon-quarterly-256.png -------------------------------------------------------------------------------- /icons/ps-export/icon-quarterly-32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adamkiss/alfred-noteplan/c8689c4779216c31628b797777b863e302ba4500/icons/ps-export/icon-quarterly-32.png -------------------------------------------------------------------------------- /icons/ps-export/icon-quarterly-64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adamkiss/alfred-noteplan/c8689c4779216c31628b797777b863e302ba4500/icons/ps-export/icon-quarterly-64.png -------------------------------------------------------------------------------- /icons/ps-export/icon-weekly-1024.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adamkiss/alfred-noteplan/c8689c4779216c31628b797777b863e302ba4500/icons/ps-export/icon-weekly-1024.png -------------------------------------------------------------------------------- /icons/ps-export/icon-weekly-128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adamkiss/alfred-noteplan/c8689c4779216c31628b797777b863e302ba4500/icons/ps-export/icon-weekly-128.png -------------------------------------------------------------------------------- /icons/ps-export/icon-weekly-16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adamkiss/alfred-noteplan/c8689c4779216c31628b797777b863e302ba4500/icons/ps-export/icon-weekly-16.png -------------------------------------------------------------------------------- /icons/ps-export/icon-weekly-256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adamkiss/alfred-noteplan/c8689c4779216c31628b797777b863e302ba4500/icons/ps-export/icon-weekly-256.png -------------------------------------------------------------------------------- /icons/ps-export/icon-weekly-32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adamkiss/alfred-noteplan/c8689c4779216c31628b797777b863e302ba4500/icons/ps-export/icon-weekly-32.png -------------------------------------------------------------------------------- /icons/ps-export/icon-weekly-64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adamkiss/alfred-noteplan/c8689c4779216c31628b797777b863e302ba4500/icons/ps-export/icon-weekly-64.png -------------------------------------------------------------------------------- /icons/ps-export/icon-yearly-1024.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adamkiss/alfred-noteplan/c8689c4779216c31628b797777b863e302ba4500/icons/ps-export/icon-yearly-1024.png -------------------------------------------------------------------------------- /icons/ps-export/icon-yearly-128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adamkiss/alfred-noteplan/c8689c4779216c31628b797777b863e302ba4500/icons/ps-export/icon-yearly-128.png -------------------------------------------------------------------------------- /icons/ps-export/icon-yearly-16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adamkiss/alfred-noteplan/c8689c4779216c31628b797777b863e302ba4500/icons/ps-export/icon-yearly-16.png -------------------------------------------------------------------------------- /icons/ps-export/icon-yearly-256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adamkiss/alfred-noteplan/c8689c4779216c31628b797777b863e302ba4500/icons/ps-export/icon-yearly-256.png -------------------------------------------------------------------------------- /icons/ps-export/icon-yearly-32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adamkiss/alfred-noteplan/c8689c4779216c31628b797777b863e302ba4500/icons/ps-export/icon-yearly-32.png -------------------------------------------------------------------------------- /icons/ps-export/icon-yearly-64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adamkiss/alfred-noteplan/c8689c4779216c31628b797777b863e302ba4500/icons/ps-export/icon-yearly-64.png -------------------------------------------------------------------------------- /lib/about.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | import 'package:alfred_noteplan/alfred.dart'; 4 | import 'package:alfred_noteplan/config.dart'; 5 | import 'package:path/path.dart'; 6 | import 'package:sqlite3/sqlite3.dart'; 7 | 8 | class About { 9 | late final String version; 10 | late final String macos_version; 11 | late final String macos_arch; 12 | late final String sqlite_version; 13 | 14 | String _r(String command, List args) { 15 | final capture = Process.runSync(command, args).stdout; 16 | return capture.trim(); 17 | } 18 | 19 | About () { 20 | version = _r('defaults', ['read', join(Config.workflow_root(), 'info'), 'version']); 21 | sqlite_version = sqlite3.version.libVersion; 22 | macos_version = _r('sw_vers', ['-productVersion']); 23 | macos_arch = _r('uname', ['-m']); 24 | } 25 | 26 | String for_clipboard() => '' 27 | 'Workflow version: ${version}\n' 28 | 'SQLite3 version: ${sqlite_version}\n' 29 | 'macOS: ${macos_version} / ${macos_arch}'; 30 | 31 | String to_alfred() => alf_to_results([ 32 | alf_item( 33 | 'Workflow information', 'Copy to clipboard', 34 | arg: for_clipboard(), variables: {'action':'copy-to-clipboard'} 35 | ), 36 | alf_item( 37 | version, 'Workflow version', 38 | valid: false, text: {'copy': version} 39 | ), 40 | alf_item( 41 | sqlite_version, 'SQLite3 version', 42 | valid: false, text: {'copy': sqlite_version} 43 | ), 44 | alf_item( 45 | macos_version, 'macOS version', 46 | valid: false, text: {'copy': macos_version} 47 | ), 48 | alf_item( 49 | macos_arch, 'mac architecture', 50 | valid: false, text: {'copy': macos_arch} 51 | ), 52 | alf_item( 53 | Config.noteplan_root, 'NotePlan root directory', 54 | valid: false, text: {'copy': Config.noteplan_root} 55 | ), 56 | ]); 57 | } -------------------------------------------------------------------------------- /lib/alfred.dart: -------------------------------------------------------------------------------- 1 | /* 2 | * Helper functions for Alfred 3 | * 4 | * - alf_to_results 5 | * - alf_invalid_item 6 | * - alf_valid_item 7 | */ 8 | 9 | import 'dart:convert'; 10 | import 'dart:io'; 11 | 12 | import 'package:alfred_noteplan/strings.dart'; 13 | 14 | String alf_to_results (List results) { 15 | return jsonEncode({'items': results}); 16 | } 17 | 18 | void alf_exit(List results) { 19 | print(alf_to_results(results)); 20 | exit(0); 21 | } 22 | 23 | Map alf_item ( 24 | String title, 25 | String subtitle, 26 | { 27 | String? uid, 28 | Map? icon, 29 | String? arg, 30 | Map? mods, 31 | Map? variables, 32 | Map? text, 33 | String? quicklookurl, 34 | bool valid = true 35 | } 36 | ) { 37 | final Map result = { 38 | 'title': title, 39 | 'subtitle': subtitle, 40 | 'valid': valid 41 | }; 42 | if (uid != null) { result['uid'] = uid; } 43 | if (icon != null) { result['icon'] = icon; } 44 | if (arg != null) { result['arg'] = arg;} 45 | if (mods != null) { result['mods'] = mods; } 46 | if (text != null) { result['text'] = text; } 47 | if (variables != null) { result['variables'] = variables; } 48 | if (quicklookurl != null) { result['quicklookurl'] = quicklookurl; } 49 | return result; 50 | } 51 | 52 | Map alf_create_item(String query) => alf_item( 53 | 'Create "${query}"', 54 | str_create_result_subtitle, 55 | icon: {'path': 'icons/icon-create.icns'}, 56 | arg: query, 57 | variables: {'action': 'create'} 58 | ); -------------------------------------------------------------------------------- /lib/code_bit.dart: -------------------------------------------------------------------------------- 1 | import 'package:alfred_noteplan/alfred.dart'; 2 | import 'package:alfred_noteplan/note.dart'; 3 | import 'package:alfred_noteplan/note_type.dart'; 4 | import 'package:alfred_noteplan/noteplan.dart'; 5 | import 'package:alfred_noteplan/strings.dart'; 6 | import 'package:path/path.dart'; 7 | import 'package:sqlite3/sqlite3.dart'; 8 | 9 | class CodeBit { 10 | final Note note; 11 | final String language; 12 | final String title; 13 | final String content; 14 | 15 | CodeBit( 16 | this.note, 17 | this.language, 18 | this.title, 19 | this.content, 20 | ); 21 | 22 | /// alfred result formatter working on raw SQL data 23 | static Map to_alfred_result(Row result) => alf_item( 24 | result['title'], 25 | '${result['language']} ✱ ${basenameWithoutExtension(result['filename'])}', 26 | arg: result['content'], 27 | icon: {'path': 'icons/icon-code-bit.icns'}, 28 | variables: {'action': 'copy-paste'}, 29 | mods: { 30 | 'cmd': { 31 | 'valid': true, 32 | 'arg': NoteType.create_from_string(result['note_type'] ?? result['type']) == NoteType.note 33 | ? Noteplan.openNoteUrl(result['filename']) 34 | : Noteplan.openCalendarUrl(basenameWithoutExtension(result['filename'])), 35 | 'subtitle': str_snippet_open_note, 36 | 'variables': {'action': 'open'} 37 | }, 38 | 'shift': { 39 | 'valid': true, 40 | 'subtitle': str_bookmark_copy, 41 | 'variables': {'action': 'copy-to-clipboard'} 42 | }, 43 | } 44 | ); 45 | 46 | } -------------------------------------------------------------------------------- /lib/config.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | import 'package:alfred_noteplan/alfred.dart'; 4 | import 'package:alfred_noteplan/strings.dart'; 5 | import 'package:intl/date_symbol_data_local.dart'; 6 | import 'package:path/path.dart'; 7 | 8 | class Config { 9 | static String noteplan_root = ''; 10 | static String locale = 'en_GB'; 11 | static String template = '' 12 | '---''\n' 13 | 'title: TITLE''\n' 14 | '---''\n' 15 | '\n'; 16 | static List ignore = []; 17 | static int week_starts_on = DateTime.monday; 18 | static bool parse_exact_date_with_space_with_day_first = false; 19 | 20 | static String path_cache_db = join(Config.noteplan_root, 'Caches', 'sync-cache.db'); 21 | 22 | static int ts() => DateTime.now().millisecondsSinceEpoch; 23 | 24 | static const Map wordWeek = { 25 | 'sk_SK': 'Týždeň', 26 | 'de_DE': 'Die Woche', 27 | }; 28 | static const String titleFormatDaily = 'dd.MM.y, EEEE'; // datetime 29 | static const String titleFormatMonthly = 'MMMM y'; // datetime 30 | static const String titleFormatWeekly = 'W%_ %y'; 31 | static const String titleFormatQuarterly = "Q%_ %y"; 32 | static const String titleFormatYearly = '%y'; 33 | 34 | static void init() { 35 | // runtime dependencies 36 | if (!Platform.environment.containsKey('user_np_root')) { 37 | Config.error(str_error_missing_root); 38 | } 39 | 40 | noteplan_root = Directory(Platform.environment['user_np_root']!).absolute.path; 41 | locale = Platform.environment['user_locale'] ?? locale; 42 | template = Platform.environment['user_new_note_template'] ?? template; 43 | ignore = (Platform.environment['user_ignore_files'] ?? '') 44 | .trim().split('\n').map((e) => e.trim()).where((e) => e.isNotEmpty) 45 | .toList(growable: false); 46 | week_starts_on = int.tryParse(Platform.environment['user_week_starts_on'] ?? '1', radix: 10) ?? week_starts_on; 47 | parse_exact_date_with_space_with_day_first = int.tryParse(Platform.environment['user_exact_day_first'] ?? '0', radix: 10) == 1; 48 | 49 | initializeDateFormatting(locale, null); 50 | } 51 | 52 | static void error(String err) { 53 | print(alf_to_results([ 54 | alf_item( 55 | err, 56 | 'There has been an error in the noteplan binary', 57 | valid: false, 58 | icon: {'path': 'icons/icon-error.icns'} 59 | ) 60 | ])); 61 | exit(1); 62 | } 63 | 64 | static final bool _current_contains_info_plist = Directory('.').listSync().map((e) => basename(e.path)).contains('info.plist'); 65 | static Directory workflow_root_as_directory() { 66 | return _current_contains_info_plist 67 | ? Directory('.') 68 | : Directory('./workflow'); 69 | } 70 | static String workflow_root() { 71 | return normalize(workflow_root_as_directory().absolute.path); 72 | } 73 | } -------------------------------------------------------------------------------- /lib/date_parser.dart: -------------------------------------------------------------------------------- 1 | import 'package:alfred_noteplan/config.dart'; 2 | import 'package:alfred_noteplan/note_type.dart'; 3 | import 'package:alfred_noteplan/date_utils.dart'; 4 | 5 | class DateParser { 6 | final String query; 7 | NoteType? type; 8 | DateTime? dt; 9 | 10 | DateParser(String q): 11 | query = q.trim() 12 | { 13 | for (var matcher in _matchers) { 14 | if (matcher.matches(query)) { 15 | type = matcher.t; 16 | dt = matcher.process(query); 17 | break; 18 | } 19 | } 20 | 21 | if (dt == null) { 22 | throw ArgumentError('Date query "${query}" invalid.'); 23 | } 24 | } 25 | 26 | (String, String) toNoteplan() => dt!.toNoteplan(type!); 27 | 28 | static int _maybeParse(String? parseMatch, int defaultValue) { 29 | return int.tryParse(parseMatch ?? '', radix: 10) ?? defaultValue; 30 | } 31 | 32 | static int _fromSymbol(String? symbolMatch) => (symbolMatch == '-') ? -1 : 1; 33 | 34 | static bool _isSymbol(String? symbolMatch) => (symbolMatch == '+' || symbolMatch == '-'); 35 | 36 | static final List _matchers = [ 37 | 38 | // word today 39 | DateParserMatcher( 40 | RegExp(r'^(?:t|to|tod|toda|today)$'), 41 | (RegExpMatch m) => DateTime.now(), 42 | NoteType.daily 43 | ), 44 | 45 | // word tomorrow 46 | DateParserMatcher( 47 | RegExp(r'^tom(?:o(?:r(?:r(?:o(?:w)?)?)?)?)?$'), 48 | (RegExpMatch m) => DateTime.now().add(Duration(days: 1)), 49 | NoteType.daily 50 | ), 51 | 52 | 53 | // word yesterday 54 | DateParserMatcher( 55 | RegExp(r'^y(?:e(?:s(?:t(?:e(?:r(?:d(?:a(?:y)?)?)?)?)?)?)?)?$'), 56 | (RegExpMatch m) => DateTime.now().subtract(Duration(days: 1)), 57 | NoteType.daily 58 | ), 59 | 60 | // exact full ymd 61 | DateParserMatcher( 62 | RegExp(r'^(\d{4})(\d{2})(\d{2})$'), 63 | (RegExpMatch m) => DateTime( 64 | int.parse(m.group(1)!, radix: 10), 65 | int.parse(m.group(2)!, radix: 10), 66 | int.parse(m.group(3)!, radix: 10) 67 | ), 68 | NoteType.daily 69 | ), 70 | 71 | // exact short ymd 72 | DateParserMatcher( 73 | RegExp(r'^(\d{2})(\d{2})(\d{2})$'), 74 | (RegExpMatch m) => DateTime( 75 | 2000 + int.parse(m.group(1)!, radix: 10), 76 | int.parse(m.group(2)!, radix: 10), 77 | int.parse(m.group(3)!, radix: 10) 78 | ), 79 | NoteType.daily 80 | ), 81 | 82 | // exact md 83 | DateParserMatcher( 84 | RegExp(r'^(\d{2})(\d{2})$'), 85 | (RegExpMatch m) => DateTime( 86 | DateTime.now().year, 87 | int.parse(m.group(1)!, radix: 10), 88 | int.parse(m.group(2)!, radix: 10) 89 | ), 90 | NoteType.daily 91 | ), 92 | 93 | // exact md 94 | DateParserMatcher( 95 | RegExp(r'^(\d{1,2})([/\.])(\d{1,2})$'), 96 | (RegExpMatch m) => DateTime( 97 | DateTime.now().year, 98 | int.parse(m.group(m.group(2)! == '/' ? 1 : 3)!, radix: 10), 99 | int.parse(m.group(m.group(2)! == '/' ? 3 : 1)!, radix: 10) 100 | ), 101 | NoteType.daily 102 | ), 103 | 104 | // exact md with space 105 | DateParserMatcher( 106 | RegExp(r'^(\d{1,2}) +(\d{1,2})$'), 107 | (RegExpMatch m) => DateTime( 108 | DateTime.now().year, 109 | int.parse(m.group(Config.parse_exact_date_with_space_with_day_first ? 2 : 1)!, radix: 10), 110 | int.parse(m.group(Config.parse_exact_date_with_space_with_day_first ? 1 : 2)!, radix: 10) 111 | ), 112 | NoteType.daily 113 | ), 114 | 115 | // daily shift: days 116 | DateParserMatcher( 117 | RegExp(r'^([-+]?)\s*?(\d*)\s*?d$'), 118 | (RegExpMatch m) { 119 | final int shift = _fromSymbol(m.group(1)) * _maybeParse(m.group(2), 1); 120 | return DateTime.now().add(Duration(days: shift)); 121 | }, 122 | NoteType.daily 123 | ), 124 | 125 | // daily shift: weeks 126 | DateParserMatcher( 127 | RegExp(r'^([-+]?)\s*?(\d+)\s*?wk?$'), 128 | (RegExpMatch m) { 129 | final int shift = _fromSymbol(m.group(1)) * _maybeParse(m.group(2), 1); 130 | return DateTime.now().add(Duration(days: shift * 7)); 131 | }, 132 | NoteType.daily 133 | ), 134 | 135 | // weekly: exact week 136 | DateParserMatcher( 137 | RegExp(r'^(?:w|wk|week)\s*?(\d+)$'), 138 | (RegExpMatch m) { 139 | final int week = int.parse(m.group(1) ?? '1', radix: 10); 140 | return DateUtils.firstWeekStart(DateTime.now().year, Config.week_starts_on).add(Duration(days: (week - 1) * 7)); 141 | }, 142 | NoteType.weekly 143 | ), 144 | 145 | // weekly, optionally shifted 146 | DateParserMatcher( 147 | RegExp(r'^(?:w|wk|week)\s*?([-+]?)\s*?(\d*)$'), 148 | (RegExpMatch m) { 149 | final int defaultValue = _isSymbol(m.group(1)) ? 1 : 0; 150 | final int shift = _fromSymbol(m.group(1)) * _maybeParse(m.group(2), defaultValue); 151 | return DateTime.now().add(Duration(days: shift * 7)); 152 | }, 153 | NoteType.weekly 154 | ), 155 | 156 | // monthly, exact month 157 | DateParserMatcher( 158 | RegExp(r'^m\s*?(\d+)$'), 159 | (RegExpMatch m) { 160 | final int month = int.parse(m.group(1) ?? '1', radix: 10); 161 | return DateTime(DateTime.now().year, month, 1); 162 | }, 163 | NoteType.monthly 164 | ), 165 | 166 | // monthly, optionally shifted 167 | DateParserMatcher( 168 | RegExp(r'^m\s*?([-+]?)\s*?(\d*)$'), 169 | (RegExpMatch m) { 170 | final int defaultValue = _isSymbol(m.group(1)) ? 1 : 0; 171 | final int shift = _fromSymbol(m.group(1)) * _maybeParse(m.group(2), defaultValue); 172 | return DateTime(DateTime.now().year, DateTime.now().month + shift, 1); 173 | }, 174 | NoteType.monthly 175 | ), 176 | 177 | // quarterly, exact quarter 178 | DateParserMatcher( 179 | RegExp(r'^q\s*?(\d+)$'), 180 | (RegExpMatch m) { 181 | final int quarter = int.parse(m.group(1) ?? '1', radix: 10); 182 | return DateTime(DateTime.now().year, quarter * 3, 1); 183 | }, 184 | NoteType.quarterly 185 | ), 186 | 187 | // quarterly, optionally shifted 188 | DateParserMatcher( 189 | RegExp(r'^q\s*?([-+]?)\s*?(\d*)$'), 190 | (RegExpMatch m) { 191 | final int defaultValue = _isSymbol(m.group(1)) ? 1 : 0; 192 | final int shift = _fromSymbol(m.group(1)) * _maybeParse(m.group(2), defaultValue); 193 | return DateTime(DateTime.now().year, DateTime.now().month + (shift * 3), 1); 194 | }, 195 | NoteType.quarterly 196 | ), 197 | 198 | // yearly, exact year 199 | DateParserMatcher( 200 | RegExp(r'^(?:y|yr|year)\s*?(\d\d)$'), 201 | (RegExpMatch m) { 202 | final int year = 2000 + int.parse(m.group(1) ?? '1', radix: 10); 203 | return DateTime(year, 1, 1); 204 | }, 205 | NoteType.yearly 206 | ), 207 | 208 | // yearly, optionally shifted 209 | DateParserMatcher( 210 | RegExp(r'^(?:y|yr|year)\s*?([-+]?)\s*?(\d*)$'), 211 | (RegExpMatch m) { 212 | final int defaultValue = _isSymbol(m.group(1)) ? 1 : 0; 213 | final int shift = _fromSymbol(m.group(1)) * _maybeParse(m.group(2), defaultValue); 214 | return DateTime(DateTime.now().year + shift, 1, 1); 215 | }, 216 | NoteType.yearly 217 | ), 218 | ]; 219 | } 220 | 221 | class DateParserMatcher { 222 | final RegExp re; 223 | final Function(RegExpMatch) func; 224 | final NoteType t; 225 | 226 | DateParserMatcher( 227 | RegExp match, 228 | DateTime Function(RegExpMatch) processor, 229 | NoteType type 230 | ): 231 | re = match, 232 | func = processor, 233 | t = type 234 | ; 235 | 236 | bool matches(String input) => re.hasMatch(input); 237 | 238 | DateTime process(String input) => func(re.firstMatch(input)!); 239 | } -------------------------------------------------------------------------------- /lib/date_utils.dart: -------------------------------------------------------------------------------- 1 | import 'package:alfred_noteplan/note_type.dart'; 2 | import 'package:alfred_noteplan/int_padding.dart'; 3 | import 'package:intl/intl.dart'; 4 | 5 | extension DateUtils on DateTime { 6 | int get quarter => int.parse(DateFormat('Q').format(this), radix: 10); 7 | int get dayOfYear => int.parse(DateFormat('D').format(this), radix: 10); 8 | 9 | /// Shift actual weekday to fake weekday based on "week starts on" 10 | /// 11 | /// ``` 12 | /// Example: Week starts on sunday 13 | /// shifter: WEEK_START - MONDAY (so monday has no change) 14 | /// shifted = weekday - shifter 15 | /// ensure positive by (shifted + 7) % 7 => 1 2 3 4 5 6 0 repeated 16 | /// decrease before modulo by 1 to shift range => 0 1 2 3 4 5 6 repeated 17 | /// increase after to correspond with weekday r=> 1 2 3 4 5 6 7 repeated 18 | /// ``` 19 | int _weekdayShift ([int weekStartsOn = DateTime.monday]) { 20 | int shiftWeek = weekStartsOn - 1; // how much we shift week against ISO 8601 21 | return ((weekday - shiftWeek + (7-1)) % 7) + 1; 22 | } 23 | int _weekOfYearBase([int weekStartsOn = DateTime.monday]) => ( 24 | (dayOfYear - _weekdayShift(weekStartsOn) + 10) 25 | / 7).floor(); 26 | int _calculateWeekOfYear([int weekStartsOn = DateTime.monday]) { 27 | int woy = _weekOfYearBase(weekStartsOn); 28 | if (woy < 1) { return DateUtils.numberOfWeeks(year - 1, weekStartsOn); } 29 | if (woy > DateUtils.numberOfWeeks(year, weekStartsOn)) { return 1; } 30 | return woy; 31 | } 32 | 33 | static int numberOfWeeks( 34 | int year, 35 | [int weekStartsOn = DateTime.monday] 36 | ) => DateTime(year, 12, 28)._weekOfYearBase(weekStartsOn); 37 | 38 | int get yearWeeks => DateUtils.numberOfWeeks(year); 39 | int adjustedYearWeeks(int weekStartsOn) => DateUtils.numberOfWeeks(year, weekStartsOn); 40 | 41 | int get weekOfYear => _calculateWeekOfYear(); 42 | int adjustedWeekOfYear(int weekStartsOn) => _calculateWeekOfYear(weekStartsOn); 43 | 44 | static DateTime firstWeekStart(int year, [int weekStartsOn = DateTime.monday]) { 45 | DateTime d = DateTime(year, 1, 1); 46 | while (d.adjustedWeekOfYear(weekStartsOn) == 1 || d.adjustedWeekOfYear(weekStartsOn) > 50) { 47 | d = d.add(Duration(days: 1)); 48 | } // repeat until adjusted week is a first day of week 2 49 | return d.subtract(Duration(days: 7)); // return the "previous week" first day 50 | } 51 | 52 | /// Convert [DateTime] to [(type, year, ??) record] based on [NoteType] 53 | (NoteType, int, int) toRecord(NoteType type, {int weekStartsWith = DateTime.monday}) { 54 | if (! NoteType.convertableToTuple3.contains(type)) { 55 | throw ArgumentError('DateTime.toRecord: can\'t convert ${type} to Record'); 56 | } 57 | 58 | switch (type) { 59 | case NoteType.weekly: 60 | final int rweek = adjustedWeekOfYear(weekStartsWith); 61 | int ryear = year; 62 | if (month == 1 && rweek > 50) { ryear -= 1; } 63 | if (month == 12 && rweek < 3) { ryear += 1;} 64 | return (type, ryear, rweek); 65 | case NoteType.monthly: return (type, year, month); 66 | case NoteType.quarterly: return (type, year, quarter); 67 | default: return (type, year, 1); 68 | } 69 | } 70 | 71 | /// Get a Noteplan note name ([String]) from a [DateTime] 72 | String toNoteplanDateString (NoteType type) { 73 | if (type == NoteType.note) { 74 | throw ArgumentError('DateTime.toNoteplanDateString: can\'t convert ${type} to filename.'); 75 | } 76 | 77 | switch (type) { 78 | case NoteType.daily: 79 | return [ 80 | year.padLeft(4), 81 | month.padLeft(2), 82 | day.padLeft(2) 83 | ].join(); 84 | default: 85 | return toRecord(type).toNoteplanDateString(); 86 | } 87 | } 88 | 89 | /// Convert to a user-formatted note title 90 | String toNoteplanTitle (NoteType type) { 91 | switch (type) { 92 | case NoteType.daily: 93 | case NoteType.monthly: 94 | return type.formatTitleDate(this); 95 | case NoteType.weekly: 96 | case NoteType.quarterly: 97 | case NoteType.yearly: 98 | final t3 = toRecord(type); 99 | return type.formatTitleWithValues(t3.$2, t3.$3); 100 | default: 101 | throw ArgumentError('DateTime.toNoteplanTitle: can\'t convert ${type} to filename.'); 102 | } 103 | } 104 | 105 | /// Returns a [(String, String) record] for a given date 106 | (String, String) toNoteplan(NoteType type) { 107 | return ( 108 | toNoteplanTitle(type), 109 | toNoteplanDateString(type) 110 | ); 111 | } 112 | } 113 | 114 | extension RecordsUtils on (NoteType, int, int) { 115 | /// shift the 'month/quarter/year' by [int] units 116 | (NoteType, int, int) shift(int change) { 117 | if (! NoteType.shiftable.contains($1)) { 118 | throw StateError('Record.shift unsupported for NoteType.weekly'); 119 | } 120 | int max = { 121 | NoteType.monthly: 12, 122 | NoteType.quarterly: 4, 123 | NoteType.yearly: 1 124 | }[$1]!; 125 | int y = $2; 126 | int x = $3 + change; 127 | while (x > max) { x -= max; y += 1; } 128 | while (x < 1) { x += max; y -= 1; } 129 | return ($1, y, x); 130 | } 131 | 132 | /// Get a Noteplan note name from [Tuple3] 133 | String toNoteplanDateString() { 134 | if ([NoteType.daily, NoteType.note].contains($1)) { 135 | throw ArgumentError( 136 | 'Record(NoteType, int, int).toNoteplanDateString: wrong NoteType in Record (${$1}, ${$2}, ${$3})' 137 | ); 138 | } 139 | 140 | switch ($1) { 141 | case NoteType.weekly: return '${$2.padLeft(4)}-W${$3.padLeft(2)}'; 142 | case NoteType.monthly: return '${$2.padLeft(4)}-${$3.padLeft(2)}'; 143 | case NoteType.quarterly: return '${$2.padLeft(4)}-Q${$3}'; 144 | default: return $2.padLeft(4); 145 | } 146 | } 147 | } -------------------------------------------------------------------------------- /lib/dbs.dart: -------------------------------------------------------------------------------- 1 | import 'package:alfred_noteplan/hyperlink.dart'; 2 | import 'package:alfred_noteplan/config.dart'; 3 | import 'package:alfred_noteplan/folder.dart'; 4 | import 'package:alfred_noteplan/note.dart'; 5 | import 'package:alfred_noteplan/note_match.dart'; 6 | import 'package:alfred_noteplan/code_bit.dart'; 7 | import 'package:alfred_noteplan/strings.dart'; 8 | import 'package:path/path.dart'; 9 | import 'package:sqlite3/sqlite3.dart'; 10 | 11 | class Dbs { 12 | late final Database _db; 13 | 14 | Dbs() { 15 | _db = sqlite3.open(join(Config.workflow_root(), 'database.sqlite3')); 16 | attach_db(Config.path_cache_db); 17 | ensure_setup(); 18 | } 19 | 20 | void dispose() => _db.dispose(); 21 | 22 | void attach_db(String path) { 23 | _db.execute(''' 24 | ATTACH DATABASE '${path}' AS cache; 25 | '''); 26 | } 27 | 28 | void ensure_setup() { 29 | _db.execute(''' 30 | CREATE VIRTUAL TABLE IF NOT EXISTS main.notes USING fts5( 31 | filename, 32 | title, 33 | content, 34 | type UNINDEXED, 35 | prefix='1 2 3' 36 | ); 37 | CREATE VIRTUAL TABLE IF NOT EXISTS main.hyperlinks USING fts5( 38 | filename UNINDEXED, 39 | note_type UNINDEXED, 40 | title, 41 | url, 42 | description, 43 | prefix='3 4 5' 44 | ); 45 | CREATE VIRTUAL TABLE IF NOT EXISTS main.code_bits USING fts5( 46 | filename UNINDEXED, 47 | note_type UNINDEXED, 48 | language, 49 | title, 50 | content, 51 | prefix='3 4 5' 52 | ); 53 | CREATE TABLE IF NOT EXISTS main.counter ( 54 | filename TEXT PRIMARY KEY, 55 | value INTEGER DEFAULT 0 56 | ); 57 | INSERT INTO main.counter(filename, value) 58 | VALUES ('__last_refresh', 0) 59 | ON CONFLICT(filename) DO NOTHING; 60 | '''); 61 | } 62 | 63 | void delete_where_filename_in(String table, Iterable notes) { 64 | _db.prepare(''' 65 | DELETE FROM main.${table} 66 | WHERE filename IN (${List.filled(notes.length, '?').join(',')}) 67 | ''').execute(notes.toList(growable: false)); 68 | } 69 | 70 | void delete_missing_notes() { 71 | _db.execute(''' 72 | WITH deleted as ( 73 | SELECT 74 | main.notes.filename as filename, 75 | cache.metadata.filename as c 76 | FROM 77 | main.notes 78 | LEFT JOIN cache.metadata USING(filename) 79 | WHERE c IS null 80 | ) 81 | DELETE FROM main.notes 82 | WHERE main.notes.filename IN (SELECT filename FROM deleted); 83 | '''); 84 | } 85 | 86 | void insert_notes(List notes) { 87 | _db.prepare(''' 88 | INSERT INTO main.notes (filename, title, content, type) 89 | VALUES ${notes.map((_) => '(?, ?, ?, ?)').join(',')} 90 | ''').execute( 91 | notes.map((e) => [ 92 | e.filename, 93 | e.title, 94 | e.content, 95 | e.type.value 96 | ]).expand((e) => e).toList(growable: false) 97 | ); 98 | } 99 | 100 | void insert_hyperlinks(List notes) { 101 | List hyperlinks = []; 102 | for (var note in notes) { 103 | hyperlinks.addAll(note.hyperlinks); 104 | } 105 | 106 | if (hyperlinks.isEmpty) { 107 | return; 108 | } 109 | 110 | _db.prepare(''' 111 | INSERT INTO main.hyperlinks (filename, note_type, title, url) 112 | VALUES ${hyperlinks.map((_) => '(?, ?, ?, ?)').join(',')} 113 | ''').execute( 114 | hyperlinks.map((e) => [ 115 | e.note.filename, 116 | e.note.type.value, 117 | e.title, 118 | e.url 119 | ]).expand((e) => e).toList(growable: false) 120 | ); 121 | } 122 | 123 | void insert_code_bits(List notes) { 124 | List code_bits = []; 125 | for (var note in notes) { 126 | code_bits.addAll(note.code_bits); 127 | } 128 | 129 | if (code_bits.isEmpty) { 130 | return; 131 | } 132 | 133 | _db.prepare(''' 134 | INSERT INTO main.code_bits (filename, note_type, language, title, content) 135 | VALUES ${code_bits.map((_) => '(?, ?, ?, ?, ?)').join(',')} 136 | ''').execute( 137 | code_bits.map((e) => [ 138 | e.note.filename, 139 | e.note.type.value, 140 | e.language, 141 | e.title, 142 | e.content, 143 | ]).expand((e) => e).toList(growable: false) 144 | ); 145 | } 146 | 147 | int get_last_update() { 148 | return _db.select('SELECT value FROM main.counter WHERE filename == "__last_refresh" limit 1;').first['value']; 149 | } 150 | 151 | void set_last_update({int? timestamp}) { 152 | _db.prepare(''' 153 | INSERT INTO main.counter(filename, value) 154 | VALUES('__last_refresh', ?) 155 | ON CONFLICT(filename) DO 156 | UPDATE SET value = excluded.value 157 | ''').execute([timestamp ?? DateTime.now().millisecondsSinceEpoch]); 158 | } 159 | 160 | List search_notes(String query, {int limit = 18}) { 161 | final String preparedQuery = query.toFtsQuery(); 162 | final ResultSet results = _db.select(''' 163 | SELECT 164 | filename, 165 | title, 166 | type, 167 | snippet(notes, 2, '${str_open_snippet}', '${str_close_snippet}', '…', 5) as snippet 168 | FROM 169 | main.notes('${preparedQuery}') 170 | ORDER BY 171 | rank 172 | LIMIT 173 | ${limit} 174 | '''); 175 | 176 | return results.map((Row row) => NoteMatch(row)).toList(growable: false); 177 | } 178 | 179 | List> search_hyperlinks(String query, {int limit = 18}) { 180 | final String preparedQuery = query.toFtsQuery(); 181 | final ResultSet results = _db.select(''' 182 | SELECT 183 | filename, 184 | note_type, 185 | title, 186 | url 187 | FROM 188 | main.hyperlinks('${preparedQuery}') 189 | ORDER BY 190 | rank 191 | LIMIT 192 | ${limit} 193 | '''); 194 | 195 | return results.map((Row result) => Hyperlink.to_alfred_result(result)).toList(growable: false); 196 | } 197 | 198 | List> search_code_bits(String query, {int limit = 18}) { 199 | final String preparedQuery = query.toFtsQuery(); 200 | final ResultSet results = _db.select(''' 201 | SELECT 202 | filename, 203 | note_type, 204 | language, 205 | title, 206 | content 207 | FROM 208 | main.code_bits('${preparedQuery}') 209 | ORDER BY 210 | rank 211 | LIMIT 212 | ${limit} 213 | '''); 214 | 215 | return results.map((Row result) => CodeBit.to_alfred_result(result)).toList(growable: false); 216 | } 217 | 218 | List> search_all(String query) { 219 | final String preparedQuery = query.toFtsQuery(); 220 | final ResultSet results = _db.select(''' 221 | SELECT 222 | 'note' as result_type, 223 | filename, 224 | title, 225 | null as language, 226 | type, 227 | snippet(notes, 2, '${str_open_snippet}', '${str_close_snippet}', '…', 5) as content, 228 | rank 229 | FROM 230 | main.notes('${preparedQuery}') 231 | UNION 232 | SELECT 233 | 'hyperlink' as result_type, 234 | filename, 235 | title, 236 | null as language, 237 | note_type, 238 | url, 239 | rank 240 | FROM 241 | main.hyperlinks('${preparedQuery}') 242 | UNION 243 | SELECT 244 | 'code bit' as result_type, 245 | filename, 246 | title, 247 | language, 248 | note_type, 249 | content, 250 | rank 251 | FROM 252 | main.code_bits('${preparedQuery}') 253 | ORDER BY 254 | rank 255 | LIMIT 256 | 18 257 | '''); 258 | 259 | return results.map((Row result) { 260 | switch (result['result_type']) { 261 | case 'note': return NoteMatch(result).to_alfred_result(); 262 | case 'hyperlink': return Hyperlink.to_alfred_result(result); 263 | case 'code bit': return CodeBit.to_alfred_result(result); 264 | default: throw Exception('Unknown result type: ${result['result_type']}'); 265 | } 266 | }).toList(); 267 | } 268 | 269 | ResultSet cache_get_updated({int since = 0}) { 270 | final String ignore_condition = Config.ignore.isEmpty 271 | ? '' 272 | : ' AND ${ 273 | Config.ignore.map((e) => 'filename NOT LIKE "${e}%"').join(' AND ') 274 | }'; 275 | 276 | return _db.select(''' 277 | SELECT filename, content, modified, note_type 278 | FROM cache.metadata 279 | WHERE 280 | is_directory = 0 281 | AND LENGTH(content) 282 | AND note_type < 2 283 | AND modified > ?${ignore_condition} 284 | ''', [since]); 285 | } 286 | 287 | List cache_list_folders(String with_title) { 288 | final folders = _db.select(''' 289 | SELECT filename 290 | FROM cache.metadata 291 | WHERE 292 | is_directory = 1 293 | AND note_type = 1 294 | AND filename NOT LIKE '@%' 295 | '''); 296 | 297 | return folders 298 | .map((e) => Folder(e, with_title)) 299 | .toList(growable: false); 300 | } 301 | } -------------------------------------------------------------------------------- /lib/folder.dart: -------------------------------------------------------------------------------- 1 | import 'package:alfred_noteplan/alfred.dart'; 2 | import 'package:alfred_noteplan/config.dart'; 3 | import 'package:alfred_noteplan/noteplan.dart'; 4 | import 'package:alfred_noteplan/strings.dart'; 5 | import 'package:path/path.dart'; 6 | import 'package:sqlite3/sqlite3.dart'; 7 | 8 | class Folder { 9 | late final String filename; 10 | final String note_title; 11 | 12 | Folder (Row row, String with_title): 13 | filename = row['filename'], 14 | note_title = with_title 15 | ; 16 | 17 | String _basename() => basename(filename); 18 | 19 | Map to_alfred() => alf_item( 20 | _basename(), 21 | str_create_folder_result_subtitle(filename, note_title), 22 | icon: {'path': 'icons/icon-folder.icns'}, 23 | arg: Noteplan.addNoteUrl(filename, Config.template.replaceAll('TITLE', note_title)), 24 | variables: {'action': 'create'} 25 | ); 26 | } -------------------------------------------------------------------------------- /lib/hyperlink.dart: -------------------------------------------------------------------------------- 1 | import 'package:alfred_noteplan/alfred.dart'; 2 | import 'package:alfred_noteplan/note.dart'; 3 | import 'package:alfred_noteplan/note_type.dart'; 4 | import 'package:alfred_noteplan/noteplan.dart'; 5 | import 'package:alfred_noteplan/strings.dart'; 6 | import 'package:path/path.dart'; 7 | import 'package:sqlite3/sqlite3.dart'; 8 | 9 | class Hyperlink{ 10 | final Note note; 11 | final String url; 12 | final String title; 13 | String? description; // currently noop 14 | 15 | Hyperlink( 16 | this.note, 17 | this.title, 18 | this.url, 19 | {this.description} 20 | ); 21 | 22 | /// alfred result formatter working on raw SQL data 23 | static Map to_alfred_result(Row result) => alf_item( 24 | result['title'], 25 | '${basenameWithoutExtension(result['filename'])} ✱ ${result['url'] ?? result['content']}', 26 | arg: result['url'] ?? result['content'], 27 | icon: {'path': 'icons/icon-hyperlink.icns'}, 28 | variables: {'action': 'open'}, 29 | mods: { 30 | 'cmd': { 31 | 'valid': true, 32 | 'arg': NoteType.create_from_string(result['note_type'] ?? result['type']) == NoteType.note 33 | ? Noteplan.openNoteUrl(result['filename']) 34 | : Noteplan.openCalendarUrl(basenameWithoutExtension(result['filename'])), 35 | 'subtitle': str_bookmark_open_note 36 | }, 37 | 'shift': { 38 | 'valid': true, 39 | 'subtitle': str_bookmark_copy, 40 | 'variables': {'action': 'copy-to-clipboard'} 41 | }, 42 | 'cmd+shift': { 43 | 'valid': true, 44 | 'subtitle': str_bookmark_copy_paste, 45 | 'variables': {'action': 'copy-paste'} 46 | }, 47 | } 48 | ); 49 | } -------------------------------------------------------------------------------- /lib/int_padding.dart: -------------------------------------------------------------------------------- 1 | extension IntPadding on int { 2 | String padLeft(int amount, [String char = '0']) { 3 | return toString().padLeft(amount, char); 4 | } 5 | } -------------------------------------------------------------------------------- /lib/note.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | 3 | import 'package:alfred_noteplan/hyperlink.dart'; 4 | import 'package:alfred_noteplan/note_type.dart'; 5 | import 'package:alfred_noteplan/code_bit.dart'; 6 | import 'package:alfred_noteplan/strings.dart'; 7 | import 'package:path/path.dart'; 8 | import 'package:sqlite3/sqlite3.dart'; 9 | 10 | class Note { 11 | final String filename; 12 | final String content_raw; 13 | final int modified; 14 | late final NoteType type; 15 | 16 | late final String title; 17 | late final String content; 18 | Map data = {}; 19 | 20 | late final List hyperlinks; 21 | late final List code_bits; 22 | 23 | Note( 24 | this.filename, 25 | this.content_raw, 26 | this.modified, 27 | final int note_type 28 | ){ 29 | final bname = basenameWithoutExtension(filename); 30 | 31 | /** NOTES */ 32 | if (note_type == 1) { 33 | type = NoteType.note; 34 | 35 | final parsed_content = _hasFrontmatterWithTitle(content_raw) 36 | ? _parse_frontmatter(content_raw) 37 | : _parse_markdown(content_raw, bname); 38 | 39 | title = parsed_content.$1; 40 | content = parsed_content.$2.cleanForFts(); 41 | hyperlinks = _parse_hyperlinks(parsed_content.$2); 42 | code_bits = _parse_code_bits(parsed_content.$2); 43 | return; 44 | } 45 | 46 | /** CALENDAR */ 47 | content = content_raw.cleanForFts(); 48 | hyperlinks = _parse_hyperlinks(content_raw); 49 | code_bits = _parse_code_bits(content_raw); 50 | 51 | if (bname.contains('W')) { // Week 52 | type = NoteType.weekly; 53 | 54 | } else if (bname.contains('Q')) { // Quarter 55 | type = NoteType.quarterly; 56 | 57 | } else if (RegExp(r'^(\d{4})-(\d{2})$').hasMatch(bname)) { // Month 58 | type = NoteType.monthly; 59 | 60 | } else if (RegExp(r'^(\d{4})$').hasMatch(bname)) { // Week 61 | type = NoteType.yearly; 62 | 63 | } else { 64 | type = NoteType.daily; 65 | } 66 | 67 | title = type.formatBasename(bname); 68 | } 69 | 70 | /// Prepare [Row] as arguments for constructor and return new [Note] 71 | static Note fromRow(Row record) { 72 | return Note( 73 | record['filename'], 74 | utf8.decode(record['content']).trim(), 75 | record['modified'], 76 | record['note_type'] 77 | ); 78 | } 79 | 80 | bool _hasFrontmatterWithTitle(String raw) { 81 | final fm = RegExp( 82 | r'^---.*?title\:\s*?(.*?)\n.*?---(.*)', 83 | caseSensitive: false, 84 | dotAll: true 85 | ); 86 | 87 | return fm.hasMatch(raw); 88 | } 89 | 90 | (String, String) _parse_frontmatter(String raw) { 91 | final fm = RegExp( 92 | r'^---.*?title\:\s*?(.*?)\n.*?---(.*)', 93 | caseSensitive: false, 94 | dotAll: true 95 | ); 96 | 97 | final match = fm.firstMatch(raw); 98 | return ( 99 | match!.group(1)!.trim(), // title 100 | match.group(2)!.trim() // content 101 | ); 102 | } 103 | 104 | (String, String) _parse_markdown(String raw, String bname) { 105 | final h1 = RegExp(r'^#\s*(.*)(?:\n|\s---)'); 106 | late String title; 107 | late String content; 108 | 109 | if (h1.hasMatch(raw)) { // has h1 as the first line 110 | final match = h1.firstMatch(raw); 111 | title = match!.group(1)!.trim(); 112 | content = raw.replaceFirst(match.group(0)!, '').trim(); 113 | } else { 114 | title = bname; 115 | content = raw; 116 | } 117 | 118 | return (title, content); 119 | } 120 | 121 | List _parse_hyperlinks(String? body) { 122 | body ??= content; 123 | final RegExp bookmark_re = RegExp(r'\[(?[^\[\]]*?)\]\((?<url>[^\[\]]*?)\)'); 124 | final Iterable<RegExpMatch> matches = bookmark_re.allMatches(body); 125 | 126 | if (matches.isEmpty) { 127 | return []; 128 | } 129 | 130 | return matches 131 | .map((RegExpMatch i) { 132 | // Discard probably Noteplan files/images 133 | if ( 134 | i.namedGroup('title')! == 'file' || 135 | i.namedGroup('title')! == 'image' 136 | ) { 137 | return null; 138 | } 139 | 140 | return Hyperlink(this, i.namedGroup('title')!, i.namedGroup('url')!); 141 | }) 142 | .where((e) => e != null) 143 | .toList(growable: false) 144 | .cast<Hyperlink>(); 145 | } 146 | 147 | List<CodeBit> _parse_code_bits(String? body) { 148 | body ??= content; 149 | 150 | final RegExp snippet_re = RegExp(r'^```(?<language>.*?)\s*\((?<title>.*?)\)?$\n(?<content>[\s\S]*?)^```', multiLine: true); 151 | final Iterable<RegExpMatch> matches = snippet_re.allMatches(body); 152 | 153 | if (matches.isEmpty) { 154 | return []; 155 | } 156 | 157 | return matches 158 | .map((RegExpMatch m) => CodeBit( 159 | this, 160 | m.namedGroup('language')!.trim(), 161 | m.namedGroup('title')!.trim(), 162 | m.namedGroup('content')!.trim(), 163 | )) 164 | .toList(growable: false) 165 | .cast<CodeBit>(); 166 | } 167 | } -------------------------------------------------------------------------------- /lib/note_match.dart: -------------------------------------------------------------------------------- 1 | import 'package:alfred_noteplan/alfred.dart'; 2 | import 'package:alfred_noteplan/config.dart'; 3 | import 'package:alfred_noteplan/note_type.dart'; 4 | import 'package:alfred_noteplan/noteplan.dart'; 5 | import 'package:alfred_noteplan/strings.dart'; 6 | import 'package:path/path.dart'; 7 | import 'package:sqlite3/sqlite3.dart'; 8 | 9 | class NoteMatch { 10 | final String filename; 11 | final String title; 12 | final String snippet; 13 | final NoteType type; 14 | 15 | NoteMatch(Row result): 16 | filename = result['filename'], 17 | title = result['title'], 18 | snippet = result['snippet'] ?? result['content'], 19 | type = NoteType.create_from_string(result['type']) 20 | ; 21 | 22 | bool _is_note() => (type == NoteType.note); 23 | 24 | String _path() => dirname(filename); 25 | String _basename() => basenameWithoutExtension(filename); 26 | String _subtitle() => _is_note() 27 | ? '${_path()} ✱ ${snippet}' 28 | : snippet; 29 | String _arg({bool sameWindow = true}) => _is_note() 30 | ? Noteplan.openNoteUrl(filename, sameWindow: sameWindow) 31 | : Noteplan.openCalendarUrl(_basename(), sameWindow: sameWindow); 32 | 33 | 34 | Map<String, dynamic> to_alfred_result() { 35 | return alf_item( 36 | title, _subtitle(), 37 | arg: _arg(), 38 | variables: {'action': 'open'}, 39 | mods: { 40 | 'cmd': { 41 | 'valid': true, 42 | 'arg': _arg(sameWindow: false), 43 | 'subtitle': str_fts_result_arg_cmd_subtitle 44 | } 45 | }, 46 | icon: {'path': 'icons/icon-${type.value}.icns'}, 47 | quicklookurl: join(Config.noteplan_root, type.np_folder, filename), 48 | ); 49 | } 50 | } -------------------------------------------------------------------------------- /lib/note_type.dart: -------------------------------------------------------------------------------- 1 | import 'package:alfred_noteplan/config.dart'; 2 | import 'package:alfred_noteplan/strings.dart'; 3 | 4 | enum NoteType { 5 | note , 6 | daily , 7 | weekly , 8 | monthly , 9 | quarterly , 10 | yearly ; 11 | 12 | static List<NoteType> shiftable = [ 13 | NoteType.monthly, 14 | NoteType.quarterly, 15 | NoteType.yearly 16 | ]; 17 | static List<NoteType> convertableToTuple3 = [ 18 | NoteType.weekly, 19 | NoteType.monthly, 20 | NoteType.quarterly, 21 | NoteType.yearly 22 | ]; 23 | 24 | String get value { 25 | switch (this) { 26 | case NoteType.note: return 'note'; 27 | case NoteType.daily: return 'daily'; 28 | case NoteType.weekly: return 'weekly'; 29 | case NoteType.monthly: return 'monthly'; 30 | case NoteType.quarterly: return 'quarterly'; 31 | case NoteType.yearly: return 'yearly'; 32 | default: return ''; // won't happen 33 | } 34 | } 35 | 36 | static NoteType create_from_string(String from) { 37 | switch (from) { 38 | case 'note': return NoteType.note; 39 | case 'daily': return NoteType.daily; 40 | case 'weekly': return NoteType.weekly; 41 | case 'monthly': return NoteType.monthly; 42 | case 'quarterly': return NoteType.quarterly; 43 | case 'yearly': return NoteType.yearly; 44 | default: throw Exception("This doesn't make sense."); 45 | } 46 | } 47 | 48 | String get np_folder { 49 | return this == NoteType.note 50 | ? 'Notes' 51 | : 'Calendar'; 52 | } 53 | 54 | String formatBasename(String bname) { 55 | // ignore: prefer_typing_uninitialized_variables 56 | var rmatch; // Re-assignable utility 57 | 58 | switch (this) { 59 | case NoteType.daily: 60 | rmatch = RegExp(r'^(\d{4})(\d{2})(\d{2})').firstMatch(bname); 61 | var dt = DateTime( 62 | int.parse(rmatch.group(1)!, radix: 10), 63 | int.parse(rmatch.group(2)!, radix: 10), 64 | int.parse(rmatch.group(3)!, radix: 10) 65 | ); 66 | return formatTitleDate(dt); 67 | case NoteType.weekly: 68 | rmatch = RegExp(r'(\d+)-[A-Z](\d+)').firstMatch(bname); 69 | return formatTitleWithValues(rmatch.group(1)!, rmatch.group(2)!); 70 | case NoteType.monthly: 71 | rmatch = RegExp(r'^(\d{4})-(\d{2})$').firstMatch(bname); 72 | var dt = DateTime( 73 | int.parse(rmatch.group(1)!, radix: 10), 74 | int.parse(rmatch.group(2)!, radix: 10) 75 | ); 76 | return formatTitleDate(dt); 77 | case NoteType.quarterly: 78 | rmatch = RegExp(r'(\d+)-[A-Z](\d+)').firstMatch(bname); 79 | return formatTitleWithValues(rmatch.group(1)!, rmatch.group(2)!); 80 | case NoteType.yearly: 81 | rmatch = RegExp(r'^(\d{4})$').firstMatch(bname); 82 | return formatTitleWithValues('%y', rmatch.group(1)!); 83 | 84 | default: throw StateError("NoteType: Can't reformat 'note' type of note."); 85 | } 86 | } 87 | 88 | /// Format [DateTime] based on Config.titleFormat<type> for this [NoteType] 89 | String formatTitleDate(DateTime dt) { 90 | switch(this) { 91 | case NoteType.daily: return Config.titleFormatDaily.splitFormatAndCapitalize(dt); 92 | case NoteType.monthly: return Config.titleFormatMonthly.splitFormatAndCapitalize(dt); 93 | default: throw StateError("NoteType: Can't format date with for ${this}."); 94 | } 95 | } 96 | 97 | /// Format pair of values as [NoteType] based on Config.titleFormat<type> 98 | String formatTitleWithValues(dynamic year, dynamic other) { 99 | switch (this) { 100 | case NoteType.weekly: 101 | return '${Config.wordWeek[Config.locale] ?? "Week"} ${ 102 | Config.titleFormatWeekly 103 | .replaceAll('%_', other.toString()) 104 | .replaceAll('%y', year.toString()) 105 | }'; 106 | case NoteType.quarterly: 107 | return Config.titleFormatQuarterly 108 | .replaceAll('%_', other.toString()) 109 | .replaceAll('%y', year.toString()); 110 | case NoteType.yearly: 111 | return Config.titleFormatYearly.replaceAll('%y', year.toString()); 112 | 113 | default: throw StateError("NoteType: Can't reformat 'note' type of note."); 114 | } 115 | } 116 | 117 | /// Format [(int, int) Record] or [(String, String) record] based on Config.titleFormat<type> for this [NoteType] 118 | String formatTitleRecord((dynamic, dynamic) t) => formatTitleWithValues(t.$1, t.$2); 119 | } 120 | -------------------------------------------------------------------------------- /lib/noteplan.dart: -------------------------------------------------------------------------------- 1 | class Noteplan { 2 | static String _url({ 3 | String method = 'openNote', 4 | Map<String, dynamic>? params 5 | }) { 6 | final String query_params = params?.keys.map((key) => '${key}=${params[key]}').join('&') ?? ''; 7 | final String url = 'noteplan://x-callback-url/${method}?${query_params}'; 8 | return Uri.encodeFull(url); // Fucking spaces again. 9 | } 10 | 11 | /// Creates a Noteplan URL for a note of type calendar (daily, weekly, monthly, …) 12 | static String openCalendarUrl(String bname, {bool sameWindow = true}) => _url( 13 | params: { 14 | 'noteDate': bname, 15 | 'useExistingSubWindow': sameWindow ? 'yes' : 'no' 16 | } 17 | ); 18 | 19 | /// Creates a Noteplan URL for a normal note 20 | static String openNoteUrl(String filename, {bool sameWindow = true}) => _url( 21 | params: { 22 | 'filename': filename, 23 | 'useExistingSubWindow': sameWindow ? 'yes' : 'no' 24 | } 25 | ); 26 | 27 | /// Creates a note creation URL. Title is expected to be a part of the body 28 | static String addNoteUrl(String folder, String body, {bool sameWindow = true}) => _url( 29 | method: 'addNote', 30 | params: { 31 | 'text': body, 32 | 'folder': folder, 33 | 'useExistingSubWindow': sameWindow ? 'yes' : 'no', 34 | 'openNote': 'yes' 35 | } 36 | ); 37 | } 38 | -------------------------------------------------------------------------------- /lib/refresh.dart: -------------------------------------------------------------------------------- 1 | import 'package:alfred_noteplan/dbs.dart'; 2 | import 'package:alfred_noteplan/note.dart'; 3 | 4 | int refresh(Dbs db, {bool force = false}) { 5 | // Delete missing notes 6 | db.delete_missing_notes(); 7 | 8 | // Get changed notes in Cache 9 | List<Note> new_notes = []; 10 | for (var result in db.cache_get_updated(since: force ? 0 : db.get_last_update())) { 11 | try { 12 | new_notes.add(Note.fromRow(result)); 13 | } catch (e) { 14 | // swallow not creation error and continue 15 | // this should skip over errors and just… not show erroneous notes 16 | } 17 | } 18 | 19 | // Delete/reinsert the notes 20 | if (new_notes.isNotEmpty) { 21 | final Iterable<String> notes_to_update = new_notes.map((e) => e.filename); 22 | 23 | db.delete_where_filename_in('notes', notes_to_update); 24 | db.insert_notes(new_notes); 25 | 26 | db.delete_where_filename_in('hyperlinks', notes_to_update); 27 | db.insert_hyperlinks(new_notes); 28 | 29 | db.delete_where_filename_in('code_bits', notes_to_update); 30 | db.insert_code_bits(new_notes); 31 | } 32 | 33 | // Save the last update and cleanup 34 | db.set_last_update(); 35 | 36 | // return number of updates 37 | return new_notes.length; 38 | } -------------------------------------------------------------------------------- /lib/strings.dart: -------------------------------------------------------------------------------- 1 | // ignore_for_file: constant_identifier_names 2 | 3 | import 'package:alfred_noteplan/config.dart'; 4 | import 'package:intl/intl.dart'; 5 | 6 | const str_usage = '' 7 | 'Usage: noteplan-[arch] [command] [arguments] \n' 8 | 'Commands: \n' 9 | ' - refresh <force?> - force is optional \n' 10 | ' - debug \n' 11 | ' - create <title> - required\n' 12 | ' - date <query> - required, begins with ">"\n' 13 | ' - search <query> - required\n' 14 | ; 15 | const str_error_missing_command = 'Command required.'; 16 | const str_error_missing_root = 'No Noteplan root set. Did you import the workflow correctly?'; 17 | const str_error_missing_args = "Commands 'create', 'date' and 'search' require arguments."; 18 | const str_error_date_unparsable = "Command 'date' expects argument in the form '><\\s>*?<query>"; 19 | 20 | const str_update_subtitle = 'The database was refreshed. You can close this prompt.'; 21 | const str_fts_result_arg_cmd_subtitle = 'Open the note in a new Noteplan window'; 22 | const str_create_result_subtitle = 'Create a new note ✱ You\'ll be asked for location in the next step'; 23 | str_create_folder_result_subtitle(String f, String t) => 'Create note "${t}" in folder "${f}"'; 24 | 25 | const str_bookmark_open_note = 'Open the note the bookmark was found in'; 26 | const str_bookmark_copy = 'Copy the URL to clipboard'; 27 | const str_bookmark_copy_paste = 'Copy the URL to clipboard and paste to frontmost app'; 28 | 29 | const str_snippet_open_note = 'Open the note the snippet was found in'; 30 | const str_snippet_copy = 'Copy the snippet to clipboard without pasting'; 31 | 32 | const str_open_snippet = '‹'; 33 | const str_close_snippet = '›'; 34 | 35 | extension StringExtensions on String { 36 | // source: https://stackoverflow.com/a/29629114/240239 37 | String toCapitalized() => length > 0 ? '${this[0].toUpperCase()}${substring(1).toLowerCase()}':''; 38 | String toTitleCase() => replaceAll(RegExp(' +'), ' ').split(' ').map((str) => str.toCapitalized()).join(' '); 39 | 40 | String splitFormatAndCapitalize(DateTime d) => split(' ') 41 | .map((part) => DateFormat(part, Config.locale).format(d)) 42 | .map((part) => part.toCapitalized()) 43 | .join(' '); 44 | 45 | String unindent() { 46 | String? first_line_whitespace = RegExp(r'^(\s*)').firstMatch(this)?.group(0); 47 | if (first_line_whitespace == null || first_line_whitespace.isEmpty) { 48 | return this; 49 | } 50 | 51 | return replaceAll(RegExp('^${first_line_whitespace}', multiLine: true), ''); 52 | } 53 | 54 | // ignore: unnecessary_this 55 | String cleanForFts() => this 56 | // remove markdown headers 57 | .replaceAll(RegExp(r'^#+\s*', multiLine: true), '') 58 | // remove markdown hr 59 | .replaceAll(RegExp(r'^\s*?\-{3,}\s*$', multiLine: true), '') 60 | // remove bullets & quotes 61 | .replaceAll(RegExp(r'^\s*?[\*>-]\s*', multiLine: true), '') 62 | // remove tasks 63 | .replaceAll(RegExp(r'^\s*?[*-]?\s*?\[.?\]\s*?', multiLine: true), '') 64 | // remove markdown styling 65 | .replaceAll(RegExp(r'[*_]'), '') 66 | // collapse whitespace 67 | .replaceAll(RegExp(r'\s+/'), ' ') 68 | .trim() // trim 69 | ; 70 | 71 | String toFtsQuery() => 72 | '${replaceAll(RegExp(r'[^\p{L}\s\d]', unicode: true), '') 73 | .replaceAll(RegExp(r'\s+'), ' ') 74 | .trim() 75 | .replaceAll(' ', '* ')}' 76 | '*' 77 | ; 78 | } -------------------------------------------------------------------------------- /pubspec.lock: -------------------------------------------------------------------------------- 1 | # Generated by pub 2 | # See https://dart.dev/tools/pub/glossary#lockfile 3 | packages: 4 | _fe_analyzer_shared: 5 | dependency: transitive 6 | description: 7 | name: _fe_analyzer_shared 8 | sha256: eb376e9acf6938204f90eb3b1f00b578640d3188b4c8a8ec054f9f479af8d051 9 | url: "https://pub.dev" 10 | source: hosted 11 | version: "64.0.0" 12 | analyzer: 13 | dependency: transitive 14 | description: 15 | name: analyzer 16 | sha256: "69f54f967773f6c26c7dcb13e93d7ccee8b17a641689da39e878d5cf13b06893" 17 | url: "https://pub.dev" 18 | source: hosted 19 | version: "6.2.0" 20 | args: 21 | dependency: transitive 22 | description: 23 | name: args 24 | sha256: eef6c46b622e0494a36c5a12d10d77fb4e855501a91c1b9ef9339326e58f0596 25 | url: "https://pub.dev" 26 | source: hosted 27 | version: "2.4.2" 28 | async: 29 | dependency: transitive 30 | description: 31 | name: async 32 | sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c" 33 | url: "https://pub.dev" 34 | source: hosted 35 | version: "2.11.0" 36 | boolean_selector: 37 | dependency: transitive 38 | description: 39 | name: boolean_selector 40 | sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66" 41 | url: "https://pub.dev" 42 | source: hosted 43 | version: "2.1.1" 44 | clock: 45 | dependency: transitive 46 | description: 47 | name: clock 48 | sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf 49 | url: "https://pub.dev" 50 | source: hosted 51 | version: "1.1.1" 52 | collection: 53 | dependency: transitive 54 | description: 55 | name: collection 56 | sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a 57 | url: "https://pub.dev" 58 | source: hosted 59 | version: "1.18.0" 60 | convert: 61 | dependency: transitive 62 | description: 63 | name: convert 64 | sha256: "0f08b14755d163f6e2134cb58222dd25ea2a2ee8a195e53983d57c075324d592" 65 | url: "https://pub.dev" 66 | source: hosted 67 | version: "3.1.1" 68 | coverage: 69 | dependency: transitive 70 | description: 71 | name: coverage 72 | sha256: "2fb815080e44a09b85e0f2ca8a820b15053982b2e714b59267719e8a9ff17097" 73 | url: "https://pub.dev" 74 | source: hosted 75 | version: "1.6.3" 76 | crypto: 77 | dependency: transitive 78 | description: 79 | name: crypto 80 | sha256: ff625774173754681d66daaf4a448684fb04b78f902da9cb3d308c19cc5e8bab 81 | url: "https://pub.dev" 82 | source: hosted 83 | version: "3.0.3" 84 | ffi: 85 | dependency: transitive 86 | description: 87 | name: ffi 88 | sha256: "7bf0adc28a23d395f19f3f1eb21dd7cfd1dd9f8e1c50051c069122e6853bc878" 89 | url: "https://pub.dev" 90 | source: hosted 91 | version: "2.1.0" 92 | file: 93 | dependency: transitive 94 | description: 95 | name: file 96 | sha256: "5fc22d7c25582e38ad9a8515372cd9a93834027aacf1801cf01164dac0ffa08c" 97 | url: "https://pub.dev" 98 | source: hosted 99 | version: "7.0.0" 100 | frontend_server_client: 101 | dependency: transitive 102 | description: 103 | name: frontend_server_client 104 | sha256: "408e3ca148b31c20282ad6f37ebfa6f4bdc8fede5b74bc2f08d9d92b55db3612" 105 | url: "https://pub.dev" 106 | source: hosted 107 | version: "3.2.0" 108 | glob: 109 | dependency: transitive 110 | description: 111 | name: glob 112 | sha256: "0e7014b3b7d4dac1ca4d6114f82bf1782ee86745b9b42a92c9289c23d8a0ab63" 113 | url: "https://pub.dev" 114 | source: hosted 115 | version: "2.1.2" 116 | http_multi_server: 117 | dependency: transitive 118 | description: 119 | name: http_multi_server 120 | sha256: "97486f20f9c2f7be8f514851703d0119c3596d14ea63227af6f7a481ef2b2f8b" 121 | url: "https://pub.dev" 122 | source: hosted 123 | version: "3.2.1" 124 | http_parser: 125 | dependency: transitive 126 | description: 127 | name: http_parser 128 | sha256: "2aa08ce0341cc9b354a498388e30986515406668dbcc4f7c950c3e715496693b" 129 | url: "https://pub.dev" 130 | source: hosted 131 | version: "4.0.2" 132 | intl: 133 | dependency: "direct main" 134 | description: 135 | name: intl 136 | sha256: "3bc132a9dbce73a7e4a21a17d06e1878839ffbf975568bc875c60537824b0c4d" 137 | url: "https://pub.dev" 138 | source: hosted 139 | version: "0.18.1" 140 | io: 141 | dependency: transitive 142 | description: 143 | name: io 144 | sha256: "2ec25704aba361659e10e3e5f5d672068d332fc8ac516421d483a11e5cbd061e" 145 | url: "https://pub.dev" 146 | source: hosted 147 | version: "1.0.4" 148 | js: 149 | dependency: transitive 150 | description: 151 | name: js 152 | sha256: f2c445dce49627136094980615a031419f7f3eb393237e4ecd97ac15dea343f3 153 | url: "https://pub.dev" 154 | source: hosted 155 | version: "0.6.7" 156 | lints: 157 | dependency: "direct dev" 158 | description: 159 | name: lints 160 | sha256: "0a217c6c989d21039f1498c3ed9f3ed71b354e69873f13a8dfc3c9fe76f1b452" 161 | url: "https://pub.dev" 162 | source: hosted 163 | version: "2.1.1" 164 | logging: 165 | dependency: transitive 166 | description: 167 | name: logging 168 | sha256: "623a88c9594aa774443aa3eb2d41807a48486b5613e67599fb4c41c0ad47c340" 169 | url: "https://pub.dev" 170 | source: hosted 171 | version: "1.2.0" 172 | matcher: 173 | dependency: transitive 174 | description: 175 | name: matcher 176 | sha256: "1803e76e6653768d64ed8ff2e1e67bea3ad4b923eb5c56a295c3e634bad5960e" 177 | url: "https://pub.dev" 178 | source: hosted 179 | version: "0.12.16" 180 | meta: 181 | dependency: transitive 182 | description: 183 | name: meta 184 | sha256: "3c74dbf8763d36539f114c799d8a2d87343b5067e9d796ca22b5eb8437090ee3" 185 | url: "https://pub.dev" 186 | source: hosted 187 | version: "1.9.1" 188 | mime: 189 | dependency: transitive 190 | description: 191 | name: mime 192 | sha256: e4ff8e8564c03f255408decd16e7899da1733852a9110a58fe6d1b817684a63e 193 | url: "https://pub.dev" 194 | source: hosted 195 | version: "1.0.4" 196 | node_preamble: 197 | dependency: transitive 198 | description: 199 | name: node_preamble 200 | sha256: "6e7eac89047ab8a8d26cf16127b5ed26de65209847630400f9aefd7cd5c730db" 201 | url: "https://pub.dev" 202 | source: hosted 203 | version: "2.0.2" 204 | package_config: 205 | dependency: transitive 206 | description: 207 | name: package_config 208 | sha256: "1c5b77ccc91e4823a5af61ee74e6b972db1ef98c2ff5a18d3161c982a55448bd" 209 | url: "https://pub.dev" 210 | source: hosted 211 | version: "2.1.0" 212 | path: 213 | dependency: "direct main" 214 | description: 215 | name: path 216 | sha256: "8829d8a55c13fc0e37127c29fedf290c102f4e40ae94ada574091fe0ff96c917" 217 | url: "https://pub.dev" 218 | source: hosted 219 | version: "1.8.3" 220 | pool: 221 | dependency: transitive 222 | description: 223 | name: pool 224 | sha256: "20fe868b6314b322ea036ba325e6fc0711a22948856475e2c2b6306e8ab39c2a" 225 | url: "https://pub.dev" 226 | source: hosted 227 | version: "1.5.1" 228 | pub_semver: 229 | dependency: transitive 230 | description: 231 | name: pub_semver 232 | sha256: "40d3ab1bbd474c4c2328c91e3a7df8c6dd629b79ece4c4bd04bee496a224fb0c" 233 | url: "https://pub.dev" 234 | source: hosted 235 | version: "2.1.4" 236 | shelf: 237 | dependency: transitive 238 | description: 239 | name: shelf 240 | sha256: ad29c505aee705f41a4d8963641f91ac4cee3c8fad5947e033390a7bd8180fa4 241 | url: "https://pub.dev" 242 | source: hosted 243 | version: "1.4.1" 244 | shelf_packages_handler: 245 | dependency: transitive 246 | description: 247 | name: shelf_packages_handler 248 | sha256: "89f967eca29607c933ba9571d838be31d67f53f6e4ee15147d5dc2934fee1b1e" 249 | url: "https://pub.dev" 250 | source: hosted 251 | version: "3.0.2" 252 | shelf_static: 253 | dependency: transitive 254 | description: 255 | name: shelf_static 256 | sha256: a41d3f53c4adf0f57480578c1d61d90342cd617de7fc8077b1304643c2d85c1e 257 | url: "https://pub.dev" 258 | source: hosted 259 | version: "1.1.2" 260 | shelf_web_socket: 261 | dependency: transitive 262 | description: 263 | name: shelf_web_socket 264 | sha256: "9ca081be41c60190ebcb4766b2486a7d50261db7bd0f5d9615f2d653637a84c1" 265 | url: "https://pub.dev" 266 | source: hosted 267 | version: "1.0.4" 268 | source_map_stack_trace: 269 | dependency: transitive 270 | description: 271 | name: source_map_stack_trace 272 | sha256: "84cf769ad83aa6bb61e0aa5a18e53aea683395f196a6f39c4c881fb90ed4f7ae" 273 | url: "https://pub.dev" 274 | source: hosted 275 | version: "2.1.1" 276 | source_maps: 277 | dependency: transitive 278 | description: 279 | name: source_maps 280 | sha256: "708b3f6b97248e5781f493b765c3337db11c5d2c81c3094f10904bfa8004c703" 281 | url: "https://pub.dev" 282 | source: hosted 283 | version: "0.10.12" 284 | source_span: 285 | dependency: transitive 286 | description: 287 | name: source_span 288 | sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c" 289 | url: "https://pub.dev" 290 | source: hosted 291 | version: "1.10.0" 292 | sqlite3: 293 | dependency: "direct main" 294 | description: 295 | name: sqlite3 296 | sha256: db65233e6b99e99b2548932f55a987961bc06d82a31a0665451fa0b4fff4c3fb 297 | url: "https://pub.dev" 298 | source: hosted 299 | version: "2.1.0" 300 | stack_trace: 301 | dependency: transitive 302 | description: 303 | name: stack_trace 304 | sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b" 305 | url: "https://pub.dev" 306 | source: hosted 307 | version: "1.11.1" 308 | stream_channel: 309 | dependency: transitive 310 | description: 311 | name: stream_channel 312 | sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7 313 | url: "https://pub.dev" 314 | source: hosted 315 | version: "2.1.2" 316 | string_scanner: 317 | dependency: transitive 318 | description: 319 | name: string_scanner 320 | sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde" 321 | url: "https://pub.dev" 322 | source: hosted 323 | version: "1.2.0" 324 | term_glyph: 325 | dependency: transitive 326 | description: 327 | name: term_glyph 328 | sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84 329 | url: "https://pub.dev" 330 | source: hosted 331 | version: "1.2.1" 332 | test: 333 | dependency: "direct dev" 334 | description: 335 | name: test 336 | sha256: "9b0dd8e36af4a5b1569029949d50a52cb2a2a2fdaa20cebb96e6603b9ae241f9" 337 | url: "https://pub.dev" 338 | source: hosted 339 | version: "1.24.6" 340 | test_api: 341 | dependency: transitive 342 | description: 343 | name: test_api 344 | sha256: "5c2f730018264d276c20e4f1503fd1308dfbbae39ec8ee63c5236311ac06954b" 345 | url: "https://pub.dev" 346 | source: hosted 347 | version: "0.6.1" 348 | test_core: 349 | dependency: transitive 350 | description: 351 | name: test_core 352 | sha256: "4bef837e56375537055fdbbbf6dd458b1859881f4c7e6da936158f77d61ab265" 353 | url: "https://pub.dev" 354 | source: hosted 355 | version: "0.5.6" 356 | typed_data: 357 | dependency: transitive 358 | description: 359 | name: typed_data 360 | sha256: facc8d6582f16042dd49f2463ff1bd6e2c9ef9f3d5da3d9b087e244a7b564b3c 361 | url: "https://pub.dev" 362 | source: hosted 363 | version: "1.3.2" 364 | vm_service: 365 | dependency: transitive 366 | description: 367 | name: vm_service 368 | sha256: c538be99af830f478718b51630ec1b6bee5e74e52c8a802d328d9e71d35d2583 369 | url: "https://pub.dev" 370 | source: hosted 371 | version: "11.10.0" 372 | watcher: 373 | dependency: transitive 374 | description: 375 | name: watcher 376 | sha256: "3d2ad6751b3c16cf07c7fca317a1413b3f26530319181b37e3b9039b84fc01d8" 377 | url: "https://pub.dev" 378 | source: hosted 379 | version: "1.1.0" 380 | web_socket_channel: 381 | dependency: transitive 382 | description: 383 | name: web_socket_channel 384 | sha256: d88238e5eac9a42bb43ca4e721edba3c08c6354d4a53063afaa568516217621b 385 | url: "https://pub.dev" 386 | source: hosted 387 | version: "2.4.0" 388 | webkit_inspection_protocol: 389 | dependency: transitive 390 | description: 391 | name: webkit_inspection_protocol 392 | sha256: "87d3f2333bb240704cd3f1c6b5b7acd8a10e7f0bc28c28dcf14e782014f4a572" 393 | url: "https://pub.dev" 394 | source: hosted 395 | version: "1.2.1" 396 | yaml: 397 | dependency: transitive 398 | description: 399 | name: yaml 400 | sha256: "75769501ea3489fca56601ff33454fe45507ea3bfb014161abc3b43ae25989d5" 401 | url: "https://pub.dev" 402 | source: hosted 403 | version: "3.1.2" 404 | sdks: 405 | dart: ">=3.0.0 <4.0.0" 406 | -------------------------------------------------------------------------------- /pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: alfred_noteplan 2 | description: Format & Refresh SQLite database for alfred-noteplan workflow 3 | version: 2.0.1-beta.1 4 | 5 | environment: 6 | sdk: '>=3.0.0 <4.0.0' 7 | 8 | dependencies: 9 | intl: ^0.18.0 10 | path: ^1.8.3 11 | sqlite3: ^2.1.0 12 | 13 | dev_dependencies: 14 | lints: ^2.0.0 15 | test: ^1.16.0 -------------------------------------------------------------------------------- /r.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env zsh 2 | # shellcheck shell=bash 3 | 4 | build:licenses () { #: Get all the licenses from pubspec.lock 5 | cat LICENSE > workflow/LICENSES 6 | echo "\n\n----------\n" >> workflow/LICENSES 7 | dart-pubspec-licenses-lite -i pubspec.lock | grep -v null >> workflow/LICENSES 8 | } 9 | 10 | build:dart () { #: Build the version for the current architecture 11 | dart compile exe bin/noteplan.dart -o "workflow/noteplan-$(uname -m)" 12 | } 13 | 14 | build:dart-local () { #: Build the version in the version controlled space 15 | dart compile exe bin/noteplan.dart -o "bin-cache/noteplan-$(uname -m)" 16 | } 17 | 18 | build:icons () { #: Build the icns file from iconsets 19 | mkdir workflow/icons 20 | rm workflow/icons/*.icns 21 | mkdir icons/iconsets 22 | rm -fr icons/iconsets/** 23 | # shellcheck disable=all 24 | for I (create folder note daily weekly monthly quarterly yearly hyperlink code-bit); do 25 | mkdir icons/iconsets/icon-$I.iconset 26 | 27 | cp icons/ps-export/icon-$I-16.png icons/iconsets/icon-$I.iconset/icon_16x16.png 28 | 29 | cp icons/ps-export/icon-$I-32.png icons/iconsets/icon-$I.iconset/icon_16x16@2x.png 30 | cp icons/ps-export/icon-$I-32.png icons/iconsets/icon-$I.iconset/icon_32x32.png 31 | 32 | cp icons/ps-export/icon-$I-64.png icons/iconsets/icon-$I.iconset/icon_32x32@2x.png 33 | cp icons/ps-export/icon-$I-128.png icons/iconsets/icon-$I.iconset/icon_128x128.png 34 | 35 | cp icons/ps-export/icon-$I-256.png icons/iconsets/icon-$I.iconset/icon_128x128@2x.png 36 | cp icons/ps-export/icon-$I-256.png icons/iconsets/icon-$I.iconset/icon_256x256.png 37 | 38 | convert icons/ps-export/icon-$I-1024.png -resize 50% icons/iconsets/icon-$I.iconset/icon_256x256@2x.png 39 | convert icons/ps-export/icon-$I-1024.png -resize 50% icons/iconsets/icon-$I.iconset/icon_512x512.png 40 | cp icons/ps-export/icon-$I-1024.png icons/iconsets/icon-$I.iconset/icon_512x512@2x.png 41 | 42 | iconutil --convert icns icons/iconsets/icon-$I.iconset 43 | done 44 | 45 | mv icons/iconsets/*.icns workflow/icons 46 | } 47 | 48 | 49 | build:plistcheck () { #: dumps the objects "prebuild" tries update with scripts in test/workflow-*.sh 50 | # should return: 51 | # "Full-text search for Noteplan" in line 1 52 | # "Opens exact Calendar note" in line 2 53 | # "Find a URL you've saved in your notes" 54 | # "Find and paste a code bit from your notes" 55 | ERROR=0 56 | [[ 57 | $(/usr/libexec/PlistBuddy -c "Print :objects:1:config:subtext" workflow/info.plist) 58 | == "Full-text search for Noteplan" 59 | ]] || ERROR=1 60 | [[ 61 | $(/usr/libexec/PlistBuddy -c "Print :objects:3:config:subtext" workflow/info.plist) 62 | == "Opens exact Calendar note" 63 | ]] || ERROR=1 64 | [[ 65 | $(/usr/libexec/PlistBuddy -c "Print :objects:6:config:subtext" workflow/info.plist) 66 | == "Find a URL you've saved in your notes" 67 | ]] || ERROR=1 68 | [[ 69 | $(/usr/libexec/PlistBuddy -c "Print :objects:8:config:subtext" workflow/info.plist) 70 | == "Find and paste a code bit from your notes" 71 | ]] || ERROR=1 72 | if (( $ERROR == 1 )); then 73 | echo "workflow/info.plist: text doesn't match. Exiting…" 74 | exit 1 75 | fi 76 | } 77 | 78 | build:script () { #: Copy the script part from the workflow.sh into info.plist 79 | cp workflow/info.plist workflow/info.plist.bak 80 | SCRIPT=`cat test/workflow-search-all.sh | sed -E 's/(["'\''])/\\\\\1/g'` 81 | /usr/libexec/PlistBuddy -c "Set :objects:1:config:script $SCRIPT" workflow/info.plist 82 | 83 | SCRIPT=`cat test/workflow-date.sh | sed -E 's/(["'\''])/\\\\\1/g'` 84 | /usr/libexec/PlistBuddy -c "Set :objects:3:config:script $SCRIPT" workflow/info.plist 85 | 86 | SCRIPT=`cat test/workflow-search-hyperlinks.sh | sed -E 's/(["'\''])/\\\\\1/g'` 87 | /usr/libexec/PlistBuddy -c "Set :objects:6:config:script $SCRIPT" workflow/info.plist 88 | 89 | SCRIPT=`cat test/workflow-search-code-bits.sh | sed -E 's/(["'\''])/\\\\\1/g'` 90 | /usr/libexec/PlistBuddy -c "Set :objects:8:config:script $SCRIPT" workflow/info.plist 91 | } 92 | 93 | build:workflow () { #: Zip the workflow folder into release/dist folder 94 | cd workflow 95 | VERSION=`/usr/libexec/PlistBuddy -c "Print :version" info.plist` 96 | BUILD=`git rev-parse --short HEAD` 97 | zip -r "../alfred-noteplan-$VERSION-$BUILD.alfredworkflow" icons/ info.plist icon.png LICENSES noteplan-arm64 noteplan-x86_64 98 | } 99 | 100 | prebuild () { #: Run the whole build - the local part 101 | # build:icons 102 | build:dart-local 103 | build:plistcheck 104 | build:script 105 | } 106 | 107 | build () { #: Run the build and packaging - on the runner 108 | build:dart 109 | cp bin-cache/noteplan-arm64 workflow/ # GA doesn't run on arm64 arch 110 | build:licenses 111 | build:workflow 112 | } 113 | 114 | version () { #: get the workflow version 115 | defaults read "$(pwd)/workflow/info" version 116 | } 117 | 118 | dev:link () { #: link the WIP version to Alfred 119 | ln -s \ 120 | /Users/adam/Code/alfred-noteplan/workflow \ 121 | /Users/adam/Code/dotfiles/config/alfred5/Alfred.alfredpreferences/workflows/alfred-noteplan; 122 | } 123 | 124 | dev:unlink () { #: remove the WIP version link from Alfred 125 | rm /Users/adam/Code/dotfiles/config/alfred5/Alfred.alfredpreferences/workflows/alfred-noteplan; 126 | } 127 | 128 | dev:plisttest () { #: list all the object to search for the trigger notes 129 | for i in {0..15}; do 130 | echo -n "$i - " 131 | /usr/libexec/PlistBuddy -c "Print :objects:${i}:config:subtext" workflow/info.plist 132 | done 133 | } 134 | 135 | test () { #: run tests 136 | zsh test/test.sh 137 | } 138 | 139 | # 140 | # BOILERPLATE 141 | # 142 | r='./r.sh' 143 | NAME='alfred-noteplan' 144 | 145 | about () { #: show help & commands 146 | echo "$NAME script runner" 147 | echo "Commands:" 148 | sed -nr 's/^(.*) \(\).* #: (.*)$/ \1 \2/p' $r | expand -20 149 | } 150 | 151 | if [[ $# -gt 0 ]]; then 152 | command="$1" 153 | shift 1 154 | if type "$command" 2>/dev/null | grep -q 'function'; then 155 | $command "$@" 156 | else 157 | about 158 | echo "No command '$command'." 159 | fi; 160 | else 161 | about 162 | fi -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # Noteplan for Alfred 2 | 3 | ![OG Social image](social.png) 4 | 5 | ## What is this 6 | 7 | Noteplan for Alfred brings all your Noteplan notes to Alfred 5 and beyond! Use it to: 8 | 9 | - 🔍 Search through all of your notes, with **full-text search** 10 | - ⚡ **Use Noteplan as link manager** - Search through all of your hyperlinks, and immediately open them in your default browser 11 | - 🌈 **Use Noteplan as snippet manager** - Search through your code bits (with title and description), and automatically paste them to your frontmost app 12 | - ✨ Create new notes easily 13 | - 📆 Go to an exact date, fuzzy date or even a weekly/monthly/quarterly note 14 | 15 | Note: this workflow **requires Alfred 5**. It uses configuration options introduced in the version 5. 16 | 17 | ## Usage 18 | - `n [Search phrase]` - Full-text search through all notes, code bits and hyperlinks 19 | - Also contains a "create new note" option 20 | - if there's no match, the note creation is the only option 21 | - `nh [Phrase]` - Search through all the hyperlinks you noted down - and open them immediately 22 | - `nc [Phrase]` - Search for all your titled code bits - and paste them to the frontmost app 23 | - `nd [date phrase]` - Very simple exact/relative date parser 24 | - `nn [Title of the note]` - Creates a new note, in the folder of your choice 25 | - `n !r` - Refresh note database 26 | - `n !rf` - Force refresh every note in the database 27 | - `n !!` - Show debug information 28 | 29 | All commands are configurable. To keep the workflow from being too complicated, if you don't wish to use a feature, just set the trigger to something complicated like `XYZ-extremely-unlikely-to-use` 30 | 31 | ### Hyperlinks 32 | 33 | Every hyperlink - `[The title and a description](https://example.com)` - is searchable, through the title and description and the link itself as well. **The default action for a hyperlink is to open it in a default browser**, to open the containing note, hit <kbd>CMD</kbd>+<kbd>↩</kbd>. 34 | 35 | ### Code bits 36 | 37 | Every block of code **with a title/description** is matched as a snippet. **Default action is "copy and paste in the frontmost app"**, to open the containing note, hit <kbd>CMD</kbd>+<kbd>↩</kbd>. 38 | 39 | #### Example code bit: 40 | 41 | ```` 42 | ```language (Title and a description in parentheses) 43 | This code bit will be matched as codebit by content, language and the title and description. 44 | ``` 45 | ```` 46 | 47 | ### Date parser 48 | - `t … today` - today's note 49 | - `y … yesterday` - yesterday's note 50 | - `tom … tomorrow` - tomorrow's note 51 | - `[20]?220401` - exact date in Ymd format, where the initial 20 is optional 52 | - `0401` - exact day, current year (month first) 53 | - `4/1` - exact day, current year (month first, leading zero optional) 54 | - `1.4` - exact day, current year (day first, leading zero optional) 55 | - `1 4` - exact day, current year (leading zero optional, d/m order configurable) 56 | - `[-+]? [number] [dw]` - relative date, number of days or weeks back and forward. spaces are optional 57 | - `[wmq]` - this week's (month's, quarter's) note 58 | - `[wmq] [number]` - weekly (monthly, quarterly) note of w/m/q X 59 | - `[wmq] -|+ [number]` - relative week's (month's, quarter's) note (spaces optional) 60 | - `yr|year` - this year's note 61 | - `yr|year [XY]` - note of the year 20XY 62 | - `yr|year -|+ [number]` - relative year (spaces optional) 63 | 64 | ## Installation 65 | 1. Download the workflow (`alfred-noteplan-X.Y.Z.alfredworkflow`) from the ['Releases' page](https://github.com/adamkiss/alfred-noteplan/releases) and import the workflow to Alfred 66 | 2. Configure the workflow as you need and want 67 | - the most important and required part is the **Noteplan root folder** 68 | - get it through `Noteplan Options` > `Sync` > `'Advanced' for your active Sync option` > `Open local database` 69 | - this will open a Finder window 70 | - in this window, with **nothing selected**, press <kbd>Command</kbd>+<kbd>Option</kbd>+<kbd>C</kbd> to copy the pathname 71 | - paste that into the workflow import window 72 | 3. Trust the app. This step is necessary because [the app is not signed](#why-all-the-warnings). 73 | 1. Type `n ` in Alfred - macOS will warn you that this app is unsigned and you can move it to bin or cancel. 74 | 2. Open **System Settings** > **Privacy & Security**, scroll down, and click "Allow Anyway". (In macOS before 13/Ventura, _System Settings_ is called _System Preferences_.) 75 | 3. Type `n ` in Alfred again - macOS will warn you _again_ that this app was downloaded from the internet and might not be safe. 76 | 4. The dialog now has an **Open** option. Click **Open** to finalize the authorization. 77 | 4. Profit! 78 | 5. You can now do a search, date query or add a new note 79 | 80 | ### Why all the warnings? 81 | To have macOS accept your app as safe, the developer needs to cryptographically sign it. That requires a $99/year Apple Developer Program, which I don't need for anything else, so the two warnings are acceptable for a free workflow in my opinion. 82 | 83 | ### Wasn't there a refresh command? 84 | There was. But with the new version, the workflow refreshes changed notes only, and that's often tiny number, so the database is updated every time this workflow is run (with debounce at ~10 seconds, so while you're querying your notes, it doesn't try to refresh every call). 85 | 86 | ## License 87 | 88 | Copyright (c) 2023 Adam Kiss 89 | 90 | Permission is hereby granted, free of charge, to any person obtaining a copy 91 | of this software and associated documentation files (the "Software"), to deal 92 | in the Software without restriction, including without limitation the rights 93 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 94 | copies of the Software, and to permit persons to whom the Software is 95 | furnished to do so, subject to the following conditions: 96 | 97 | The above copyright notice and this permission notice shall be included in all 98 | copies or substantial portions of the Software. 99 | 100 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 101 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 102 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 103 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 104 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 105 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 106 | SOFTWARE. -------------------------------------------------------------------------------- /social.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adamkiss/alfred-noteplan/c8689c4779216c31628b797777b863e302ba4500/social.png -------------------------------------------------------------------------------- /test/date_parser_test.dart: -------------------------------------------------------------------------------- 1 | import 'package:alfred_noteplan/config.dart'; 2 | import 'package:alfred_noteplan/date_parser.dart'; 3 | import 'package:alfred_noteplan/date_utils.dart'; 4 | import 'package:alfred_noteplan/note_type.dart'; 5 | import 'package:alfred_noteplan/int_padding.dart'; 6 | import 'package:intl/date_symbol_data_local.dart'; 7 | import 'package:test/test.dart'; 8 | 9 | final DateTime _now = DateTime.now(); 10 | 11 | String dpfn(String query) => DateParser(query).toNoteplan().$2; 12 | 13 | void main() { 14 | initializeDateFormatting('en_GB', null); 15 | 16 | test('query start formats', () { 17 | expect(dpfn('today'), _now.toNoteplanDateString(NoteType.daily)); 18 | expect(dpfn(' today'), _now.toNoteplanDateString(NoteType.daily)); 19 | }); 20 | 21 | group('daily: words', () { 22 | test('today', () { 23 | expect(dpfn('t'), _now.toNoteplanDateString(NoteType.daily)); 24 | expect(dpfn('to'), _now.toNoteplanDateString(NoteType.daily)); 25 | expect(dpfn('tod'), _now.toNoteplanDateString(NoteType.daily)); 26 | expect(dpfn('toda'), _now.toNoteplanDateString(NoteType.daily)); 27 | expect(dpfn('today'), _now.toNoteplanDateString(NoteType.daily)); 28 | }); 29 | test('tomorrow', () { 30 | expect(dpfn('tom'), _now.add(Duration(days: 1)).toNoteplanDateString(NoteType.daily)); 31 | expect(dpfn('tomor'), _now.add(Duration(days: 1)).toNoteplanDateString(NoteType.daily)); 32 | expect(dpfn('tomorr'), _now.add(Duration(days: 1)).toNoteplanDateString(NoteType.daily)); 33 | expect(dpfn('tomorrow'), _now.add(Duration(days: 1)).toNoteplanDateString(NoteType.daily)); 34 | }); 35 | test('yesterday', () { 36 | expect(dpfn('y'), _now.subtract(Duration(days: 1)).toNoteplanDateString(NoteType.daily)); 37 | expect(dpfn('ye'), _now.subtract(Duration(days: 1)).toNoteplanDateString(NoteType.daily)); 38 | expect(dpfn('yes'), _now.subtract(Duration(days: 1)).toNoteplanDateString(NoteType.daily)); 39 | expect(dpfn('yest'), _now.subtract(Duration(days: 1)).toNoteplanDateString(NoteType.daily)); 40 | expect(dpfn('yester'), _now.subtract(Duration(days: 1)).toNoteplanDateString(NoteType.daily)); 41 | expect(dpfn('yesterday'), _now.subtract(Duration(days: 1)).toNoteplanDateString(NoteType.daily)); 42 | }); 43 | }); 44 | 45 | group('daily: exact', () { 46 | test('Ymd', () { 47 | expect(dpfn('20221211'), DateTime(2022, 12, 11).toNoteplanDateString(NoteType.daily)); 48 | expect(dpfn('20220711'), DateTime(2022, 07, 11).toNoteplanDateString(NoteType.daily)); 49 | expect(dpfn('20230101'), DateTime(2023, 01, 01).toNoteplanDateString(NoteType.daily)); 50 | expect(dpfn('20200229'), DateTime(2020, 02, 29).toNoteplanDateString(NoteType.daily)); 51 | expect(dpfn('20230229'), DateTime(2023, 03, 01).toNoteplanDateString(NoteType.daily)); 52 | expect(dpfn('20220229'), DateTime(2022, 03, 01).toNoteplanDateString(NoteType.daily)); 53 | expect(dpfn('20230432'), DateTime(2023, 05, 02).toNoteplanDateString(NoteType.daily)); 54 | }); 55 | test('short Ymd', () { 56 | expect(dpfn('221211'), DateTime(2022, 12, 11).toNoteplanDateString(NoteType.daily)); 57 | expect(dpfn('220611'), DateTime(2022, 06, 11).toNoteplanDateString(NoteType.daily)); 58 | expect(dpfn('230101'), DateTime(2023, 01, 01).toNoteplanDateString(NoteType.daily)); 59 | expect(dpfn('200229'), DateTime(2020, 02, 29).toNoteplanDateString(NoteType.daily)); 60 | expect(dpfn('230229'), DateTime(2023, 03, 01).toNoteplanDateString(NoteType.daily)); 61 | expect(dpfn('220229'), DateTime(2022, 03, 01).toNoteplanDateString(NoteType.daily)); 62 | expect(dpfn('210432'), DateTime(2021, 05, 02).toNoteplanDateString(NoteType.daily)); 63 | }); 64 | test('month/day only', () { 65 | expect(dpfn('1211'), DateTime(DateTime.now().year, 12, 11).toNoteplanDateString(NoteType.daily)); 66 | expect(dpfn('0411'), DateTime(DateTime.now().year, 04, 11).toNoteplanDateString(NoteType.daily)); 67 | expect(dpfn('0101'), DateTime(DateTime.now().year, 01, 01).toNoteplanDateString(NoteType.daily)); 68 | expect(dpfn('0229'), DateTime(DateTime.now().year, 02, 29).toNoteplanDateString(NoteType.daily)); 69 | expect(dpfn('0432'), DateTime(DateTime.now().year, 05, 02).toNoteplanDateString(NoteType.daily)); 70 | }); 71 | test('month/day with a symbol', () { 72 | expect(dpfn('1/1'), DateTime(DateTime.now().year, 1, 1).toNoteplanDateString(NoteType.daily)); 73 | expect(dpfn('1.1'), DateTime(DateTime.now().year, 1, 1).toNoteplanDateString(NoteType.daily)); 74 | expect(dpfn('01.1'), DateTime(DateTime.now().year, 1, 1).toNoteplanDateString(NoteType.daily)); 75 | expect(dpfn('11.1'), DateTime(DateTime.now().year, 1, 11).toNoteplanDateString(NoteType.daily)); 76 | expect(dpfn('1.11'), DateTime(DateTime.now().year, 11, 1).toNoteplanDateString(NoteType.daily)); 77 | expect(dpfn('11/1'), DateTime(DateTime.now().year, 11, 1).toNoteplanDateString(NoteType.daily)); 78 | expect(dpfn('1/11'), DateTime(DateTime.now().year, 1, 11).toNoteplanDateString(NoteType.daily)); 79 | }); 80 | test('month/day with a space', () { 81 | Config.parse_exact_date_with_space_with_day_first = true; 82 | expect(dpfn('1 4'), DateTime(DateTime.now().year, 4, 1).toNoteplanDateString(NoteType.daily)); 83 | expect(dpfn('12 13'), DateTime(DateTime.now().year+1, 01, 12).toNoteplanDateString(NoteType.daily)); 84 | 85 | Config.parse_exact_date_with_space_with_day_first = false; 86 | expect(dpfn('1 4'), DateTime(DateTime.now().year, 01, 04).toNoteplanDateString(NoteType.daily)); 87 | expect(dpfn('1 04'), DateTime(DateTime.now().year, 01, 4).toNoteplanDateString(NoteType.daily)); 88 | expect(dpfn('12 13'), DateTime(DateTime.now().year, 12, 13).toNoteplanDateString(NoteType.daily)); 89 | }); 90 | }); 91 | 92 | group('daily: movement', () { 93 | test('days', () { 94 | expect(dpfn('+2d'), _now.add(Duration(days: 2)).toNoteplanDateString(NoteType.daily)); 95 | expect(dpfn('+ 2d'), _now.add(Duration(days: 2)).toNoteplanDateString(NoteType.daily)); 96 | expect(dpfn('2d'), _now.add(Duration(days: 2)).toNoteplanDateString(NoteType.daily)); 97 | expect(dpfn('+2 d'), _now.add(Duration(days: 2)).toNoteplanDateString(NoteType.daily)); 98 | expect(dpfn('+ 2 d'), _now.add(Duration(days: 2)).toNoteplanDateString(NoteType.daily)); 99 | expect(dpfn('2 d'), _now.add(Duration(days: 2)).toNoteplanDateString(NoteType.daily)); 100 | expect(dpfn(' 2 d'), _now.add(Duration(days: 2)).toNoteplanDateString(NoteType.daily)); 101 | expect(dpfn('+ 14 d'), _now.add(Duration(days: 14)).toNoteplanDateString(NoteType.daily)); 102 | expect(dpfn('+12 d'), _now.add(Duration(days: 12)).toNoteplanDateString(NoteType.daily)); 103 | expect(dpfn('-3d'), _now.subtract(Duration(days: 3)).toNoteplanDateString(NoteType.daily)); 104 | expect(dpfn('- 1d'), _now.subtract(Duration(days: 1)).toNoteplanDateString(NoteType.daily)); 105 | expect(dpfn('- 4 d'), _now.subtract(Duration(days: 4)).toNoteplanDateString(NoteType.daily)); 106 | expect(dpfn('-2 d'), _now.subtract(Duration(days: 2)).toNoteplanDateString(NoteType.daily)); 107 | expect(dpfn('- 10d'), _now.subtract(Duration(days: 10)).toNoteplanDateString(NoteType.daily)); 108 | }); 109 | test('weeks', () { 110 | expect(dpfn('+2w'), _now.add(Duration(days: 2 * 7)).toNoteplanDateString(NoteType.daily)); 111 | expect(dpfn('+ 2w'), _now.add(Duration(days: 2 * 7)).toNoteplanDateString(NoteType.daily)); 112 | expect(dpfn('2w'), _now.add(Duration(days: 2 * 7)).toNoteplanDateString(NoteType.daily)); 113 | expect(dpfn('+2wk'), _now.add(Duration(days: 2 * 7)).toNoteplanDateString(NoteType.daily)); 114 | expect(dpfn('+ 2wk'), _now.add(Duration(days: 2 * 7)).toNoteplanDateString(NoteType.daily)); 115 | expect(dpfn('2wk'), _now.add(Duration(days: 2 * 7)).toNoteplanDateString(NoteType.daily)); 116 | expect(dpfn('-3w'), _now.subtract(Duration(days: 3 * 7)).toNoteplanDateString(NoteType.daily)); 117 | expect(dpfn('- 1w'), _now.subtract(Duration(days: 1 * 7)).toNoteplanDateString(NoteType.daily)); 118 | expect(dpfn('-4wk'), _now.subtract(Duration(days: 4 * 7)).toNoteplanDateString(NoteType.daily)); 119 | expect(dpfn('- 2wk'), _now.subtract(Duration(days: 2 * 7)).toNoteplanDateString(NoteType.daily)); 120 | }); 121 | }); 122 | 123 | DateTime dt; 124 | group('other', () { 125 | test('week', () { 126 | expect(dpfn('w'), _now.toNoteplanDateString(NoteType.weekly), reason: 'w'); 127 | expect(dpfn('wk'), _now.toNoteplanDateString(NoteType.weekly), reason: 'wk'); 128 | expect(dpfn('week'), _now.toNoteplanDateString(NoteType.weekly), reason: 'week'); 129 | dt = _now.add(Duration(days: 1 * 7)); 130 | expect(dpfn('w +'), dt.toNoteplanDateString(NoteType.weekly), reason: 'w +'); 131 | dt = _now.add(Duration(days: 1 * 7)); 132 | expect(dpfn('w +1'), dt.toNoteplanDateString(NoteType.weekly), reason: 'w +1'); 133 | dt = _now.add(Duration(days: 2 * 7)); 134 | expect(dpfn('w + 2'), dt.toNoteplanDateString(NoteType.weekly), reason: 'w + 2'); 135 | dt = _now.add(Duration(days: 23 * 7)); 136 | expect(dpfn('w+ 23'), dt.toNoteplanDateString(NoteType.weekly), reason: 'w+ 23'); 137 | dt = _now.add(Duration(days: -1 * 7)); 138 | expect(dpfn('w-'), dt.toNoteplanDateString(NoteType.weekly), reason: 'w-'); 139 | dt = _now.add(Duration(days: -1 * 7)); 140 | expect(dpfn('w -1'), dt.toNoteplanDateString(NoteType.weekly), reason: 'w -1'); 141 | dt = _now.add(Duration(days: -2 * 7)); 142 | expect(dpfn('w - 2'), dt.toNoteplanDateString(NoteType.weekly), reason: 'w - 2'); 143 | dt = _now.add(Duration(days: -23 * 7)); 144 | expect(dpfn('w- 23'), dt.toNoteplanDateString(NoteType.weekly), reason: 'w- 23'); 145 | dt = _now.add(Duration(days: 1 * 7)); 146 | expect(dpfn('wk +'), dt.toNoteplanDateString(NoteType.weekly), reason: 'wk +'); 147 | dt = _now.add(Duration(days: 1 * 7)); 148 | expect(dpfn('wk +1'), dt.toNoteplanDateString(NoteType.weekly), reason: 'wk +1'); 149 | dt = _now.add(Duration(days: 2 * 7)); 150 | expect(dpfn('wk + 2'), dt.toNoteplanDateString(NoteType.weekly), reason: 'wk + 2'); 151 | dt = _now.add(Duration(days: 23 * 7)); 152 | expect(dpfn('wk+ 23'), dt.toNoteplanDateString(NoteType.weekly), reason: 'wk+ 23'); 153 | dt = _now.add(Duration(days: -1 * 7)); 154 | expect(dpfn('wk-'), dt.toNoteplanDateString(NoteType.weekly), reason: 'wk-'); 155 | dt = _now.add(Duration(days: -1 * 7)); 156 | expect(dpfn('wk -1'), dt.toNoteplanDateString(NoteType.weekly), reason: 'wk -1'); 157 | dt = _now.add(Duration(days: -2 * 7)); 158 | expect(dpfn('wk - 2'), dt.toNoteplanDateString(NoteType.weekly), reason: 'wk - 2'); 159 | dt = _now.add(Duration(days: -23 * 7)); 160 | expect(dpfn('wk- 23'), dt.toNoteplanDateString(NoteType.weekly), reason: 'wk- 23'); 161 | dt = _now.add(Duration(days: 1 * 7)); 162 | expect(dpfn('week +'), dt.toNoteplanDateString(NoteType.weekly), reason: 'week +'); 163 | dt = _now.add(Duration(days: 1 * 7)); 164 | expect(dpfn('week +1'), dt.toNoteplanDateString(NoteType.weekly), reason: 'week +1'); 165 | dt = _now.add(Duration(days: 2 * 7)); 166 | expect(dpfn('week + 2'), dt.toNoteplanDateString(NoteType.weekly), reason: 'week + 2'); 167 | dt = _now.add(Duration(days: 23 * 7)); 168 | expect(dpfn('week+ 23'), dt.toNoteplanDateString(NoteType.weekly), reason: 'week+ 23'); 169 | dt = _now.add(Duration(days: -1 * 7)); 170 | expect(dpfn('week-'), dt.toNoteplanDateString(NoteType.weekly), reason: 'week-'); 171 | dt = _now.add(Duration(days: -1 * 7)); 172 | expect(dpfn('week -1'), dt.toNoteplanDateString(NoteType.weekly), reason: 'week -1'); 173 | dt = _now.add(Duration(days: -2 * 7)); 174 | expect(dpfn('week - 2'), dt.toNoteplanDateString(NoteType.weekly), reason: 'week - 2'); 175 | dt = _now.add(Duration(days: -23 * 7)); 176 | expect(dpfn('week- 23'), dt.toNoteplanDateString(NoteType.weekly), reason: 'week- 23'); 177 | }); 178 | test('week - exact', () { 179 | expect(dpfn('w2'), '${_now.year}-W${2.padLeft(2)}', reason: 'exact week: 2'); 180 | expect(dpfn('wk2'), '${_now.year}-W${2.padLeft(2)}', reason: 'exact week: 2'); 181 | expect(dpfn('week2'), '${_now.year}-W${2.padLeft(2)}', reason: 'exact week: 2'); 182 | expect(dpfn('w 30'), '${_now.year}-W${30.padLeft(2)}', reason: 'exact week: 30 + space'); 183 | expect(dpfn('wk 12'), '${_now.year}-W${12.padLeft(2)}', reason: 'exact week: 12 + space'); 184 | expect(dpfn('week 24'), '${_now.year}-W${24.padLeft(2)}', reason: 'exact week: 24 + space'); 185 | }); 186 | test('month', () { 187 | // note: if day > 28, movement around february might overflow to march 188 | expect(dpfn('m'), _now.toNoteplanDateString(NoteType.monthly), reason: 'm'); 189 | dt = DateTime(_now.year, _now.month + 1, 20); 190 | expect(dpfn('m +'), dt.toNoteplanDateString(NoteType.monthly), reason: 'm +'); 191 | dt = DateTime(_now.year, _now.month + 1, 20); 192 | expect(dpfn('m +1'), dt.toNoteplanDateString(NoteType.monthly), reason: 'm +1'); 193 | dt = DateTime(_now.year, _now.month + 2, 20); 194 | expect(dpfn('m + 2'), dt.toNoteplanDateString(NoteType.monthly), reason: 'm + 2'); 195 | dt = DateTime(_now.year, _now.month + 23, 20); 196 | expect(dpfn('m+ 23'), dt.toNoteplanDateString(NoteType.monthly), reason: 'm+ 23'); 197 | dt = DateTime(_now.year, _now.month + -1, 20); 198 | expect(dpfn('m-'), dt.toNoteplanDateString(NoteType.monthly), reason: 'm-'); 199 | dt = DateTime(_now.year, _now.month + -1, 20); 200 | expect(dpfn('m -1'), dt.toNoteplanDateString(NoteType.monthly), reason: 'm -1'); 201 | dt = DateTime(_now.year, _now.month + -2, 20); 202 | expect(dpfn('m - 2'), dt.toNoteplanDateString(NoteType.monthly), reason: 'm - 2'); 203 | dt = DateTime(_now.year, _now.month + -23, 20); 204 | expect(dpfn('m- 23'), dt.toNoteplanDateString(NoteType.monthly), reason: 'm- 23'); 205 | }); 206 | test('month - exact', () { 207 | expect(dpfn('m2'), '${_now.year}-${2.padLeft(2)}', reason: 'exact month: 2'); 208 | expect(dpfn('m 2'), '${_now.year}-${2.padLeft(2)}', reason: 'exact month: 2+space'); 209 | expect(dpfn('m12'), '${_now.year}-${12.padLeft(2)}', reason: 'exact month: 12'); 210 | expect(dpfn('m 12'),'${_now.year}-${12.padLeft(2)}', reason: 'exact month: 12+space'); 211 | expect(dpfn('m13'), '${_now.year+1}-01', reason: 'exact month: 13'); 212 | expect(dpfn('m 13'),'${_now.year+1}-01', reason: 'exact month: 13+space'); 213 | }); 214 | test('quarter', () { 215 | expect(dpfn('q'), _now.toNoteplanDateString(NoteType.quarterly)); 216 | dt = DateTime(_now.year, _now.month + 3*1, _now.day); 217 | expect(dpfn('q +'), dt.toNoteplanDateString(NoteType.quarterly)); 218 | dt = DateTime(_now.year, _now.month + 3*1, _now.day); 219 | expect(dpfn('q +1'), dt.toNoteplanDateString(NoteType.quarterly)); 220 | dt = DateTime(_now.year, _now.month + 3*2, _now.day); 221 | expect(dpfn('q + 2'), dt.toNoteplanDateString(NoteType.quarterly)); 222 | dt = DateTime(_now.year, _now.month + 3*23, _now.day); 223 | expect(dpfn('q+ 23 '), dt.toNoteplanDateString(NoteType.quarterly)); 224 | dt = DateTime(_now.year, _now.month + 3*-1, _now.day); 225 | expect(dpfn('q -'), dt.toNoteplanDateString(NoteType.quarterly)); 226 | dt = DateTime(_now.year, _now.month + 3*-1, _now.day); 227 | expect(dpfn('q -1'), dt.toNoteplanDateString(NoteType.quarterly)); 228 | dt = DateTime(_now.year, _now.month + 3*-2, _now.day); 229 | expect(dpfn('q - 2'), dt.toNoteplanDateString(NoteType.quarterly)); 230 | dt = DateTime(_now.year, _now.month + 3*-23, _now.day); 231 | expect(dpfn('q- 23 '), dt.toNoteplanDateString(NoteType.quarterly)); 232 | }); 233 | test('quarter - exact', () { 234 | expect(dpfn('q2'), '${_now.year}-Q2', reason: 'exact quarter: 2'); 235 | expect(dpfn('q 2'), '${_now.year}-Q2', reason: 'exact quarter: 2+space'); 236 | expect(dpfn('q04'), '${_now.year}-Q4', reason: 'exact quarter: 04'); 237 | expect(dpfn('q 4'), '${_now.year}-Q4', reason: 'exact quarter: 4+space'); 238 | expect(dpfn('q06'), '${_now.year+1}-Q2', reason: 'exact quarter: 06'); 239 | expect(dpfn('q 06'),'${_now.year+1}-Q2', reason: 'exact quarter: 06+space'); 240 | }); 241 | test('year', () { 242 | expect(dpfn('yr'), _now.toNoteplanDateString(NoteType.yearly)); 243 | expect(dpfn('year'), _now.toNoteplanDateString(NoteType.yearly)); 244 | dt = DateTime(_now.year + 1, _now.month, _now.day); 245 | expect(dpfn('y+'), dt.toNoteplanDateString(NoteType.yearly)); 246 | dt = DateTime(_now.year + 1, _now.month, _now.day); 247 | expect(dpfn('y +1'), dt.toNoteplanDateString(NoteType.yearly)); 248 | dt = DateTime(_now.year + 1, _now.month, _now.day); 249 | expect(dpfn('yr+'), dt.toNoteplanDateString(NoteType.yearly)); 250 | dt = DateTime(_now.year + 1, _now.month, _now.day); 251 | expect(dpfn('yr +1'), dt.toNoteplanDateString(NoteType.yearly)); 252 | dt = DateTime(_now.year + 2, _now.month, _now.day); 253 | expect(dpfn('yr + 2'), dt.toNoteplanDateString(NoteType.yearly)); 254 | dt = DateTime(_now.year + 23, _now.month, _now.day); 255 | expect(dpfn('yr+ 23'), dt.toNoteplanDateString(NoteType.yearly)); 256 | dt = DateTime(_now.year + -1, _now.month, _now.day); 257 | expect(dpfn('yr-'), dt.toNoteplanDateString(NoteType.yearly)); 258 | dt = DateTime(_now.year + -1, _now.month, _now.day); 259 | expect(dpfn('yr -1'), dt.toNoteplanDateString(NoteType.yearly)); 260 | dt = DateTime(_now.year + -2, _now.month, _now.day); 261 | expect(dpfn('yr - 2'), dt.toNoteplanDateString(NoteType.yearly)); 262 | dt = DateTime(_now.year + -23, _now.month, _now.day); 263 | expect(dpfn('yr- 23'), dt.toNoteplanDateString(NoteType.yearly)); 264 | }); 265 | test('year - exact', () { 266 | expect(dpfn('y23'), '2023', reason: 'exact year: 23'); 267 | expect(dpfn('y 23'), '2023', reason: 'exact year: 23+space'); 268 | expect(dpfn('yr22'), '2022', reason: 'exact year: 22'); 269 | expect(dpfn('yr 24'), '2024', reason: 'exact year: 24+space'); 270 | expect(dpfn('year22'), '2022', reason: 'exact year: 22'); 271 | expect(dpfn('year 24'), '2024', reason: 'exact year: 24+space'); 272 | }); 273 | }); 274 | 275 | } -------------------------------------------------------------------------------- /test/date_utils_test.dart: -------------------------------------------------------------------------------- 1 | import 'package:alfred_noteplan/config.dart'; 2 | import 'package:alfred_noteplan/date_utils.dart'; 3 | import 'package:alfred_noteplan/note_type.dart'; 4 | import 'package:test/test.dart'; 5 | 6 | void main() { 7 | test('Week of the year: Adjusting from ISO 8601 to Noteplan', () { 8 | expect(DateTime(2023, 1, 1).adjustedWeekOfYear(DateTime.monday), 52, reason: '2023 - wk starts on: monday'); 9 | expect(DateTime(2023, 1, 1).adjustedWeekOfYear(DateTime.tuesday), 52, reason: '2023 - wk starts on: tuesday'); 10 | expect(DateTime(2023, 1, 1).adjustedWeekOfYear(DateTime.wednesday), 53, reason: '2023 - wk starts on: wednesday'); 11 | expect(DateTime(2023, 1, 1).adjustedWeekOfYear(DateTime.thursday), 1, reason: '2023 - wk starts on: thursday'); 12 | expect(DateTime(2023, 1, 1).adjustedWeekOfYear(DateTime.friday), 1, reason: '2023 - wk starts on: friday'); 13 | expect(DateTime(2023, 1, 1).adjustedWeekOfYear(DateTime.saturday), 1, reason: '2023 - wk starts on: saturday'); 14 | expect(DateTime(2023, 1, 1).adjustedWeekOfYear(DateTime.sunday), 1, reason: '2023 - wk starts on: sunday'); 15 | 16 | expect(DateTime(2015, 1, 1).adjustedWeekOfYear(DateTime.monday), 1, reason: '2015 - wk starts on: monday'); 17 | expect(DateTime(2015, 1, 1).adjustedWeekOfYear(DateTime.tuesday), 1, reason: '2015 - wk starts on: tuesday'); 18 | expect(DateTime(2015, 1, 1).adjustedWeekOfYear(DateTime.wednesday), 1, reason: '2015 - wk starts on: wednesday'); 19 | expect(DateTime(2015, 1, 1).adjustedWeekOfYear(DateTime.thursday), 1, reason: '2015 - wk starts on: thursday'); 20 | expect(DateTime(2015, 1, 1).adjustedWeekOfYear(DateTime.friday), 52, reason: '2015 - wk starts on: friday'); 21 | expect(DateTime(2015, 1, 1).adjustedWeekOfYear(DateTime.saturday), 52, reason: '2015 - wk starts on: saturday'); 22 | expect(DateTime(2015, 1, 1).adjustedWeekOfYear(DateTime.sunday), 53, reason: '2015 - wk starts on: sunday'); 23 | }); 24 | 25 | group('Date Utils', () { 26 | test('Day of the year', () { 27 | expect(DateTime(2023, 1, 1).dayOfYear, 1); 28 | expect(DateTime(2023, 4, 1).dayOfYear, 91); 29 | expect(DateTime(2023, 7, 1).dayOfYear, 182); 30 | expect(DateTime(2023, 10, 1).dayOfYear, 274); 31 | expect(DateTime(2023, 1, 31).dayOfYear, 31); 32 | expect(DateTime(2023, 4, 30).dayOfYear, 120); 33 | expect(DateTime(2023, 7, 31).dayOfYear, 212); 34 | expect(DateTime(2023, 10, 31).dayOfYear, 304); 35 | expect(DateTime(2023, 2, 29).dayOfYear, 60); // 1.3. 36 | }); 37 | test('Week of the year: ISO 8601', () { 38 | expect(DateTime(2023, 1, 1).weekOfYear, 52); 39 | expect(DateTime(2023, 4, 1).weekOfYear, 13); 40 | expect(DateTime(2023, 7, 1).weekOfYear, 26); 41 | expect(DateTime(2023, 10, 1).weekOfYear, 39); 42 | expect(DateTime(2023, 1, 31).weekOfYear, 5); 43 | expect(DateTime(2023, 4, 30).weekOfYear, 17); 44 | expect(DateTime(2023, 7, 31).weekOfYear, 31); 45 | expect(DateTime(2023, 10, 31).weekOfYear, 44); 46 | expect(DateTime(2023, 2, 29).weekOfYear, 9); // 1.3. 47 | }); 48 | test('Week of the year: Week starts with Sunday', () { 49 | expect(DateTime(2023, 1, 1).adjustedWeekOfYear(DateTime.sunday), 1); 50 | expect(DateTime(2023, 4, 1).adjustedWeekOfYear(DateTime.sunday), 13); 51 | expect(DateTime(2023, 7, 1).adjustedWeekOfYear(DateTime.sunday), 26); 52 | expect(DateTime(2023, 10, 1).adjustedWeekOfYear(DateTime.sunday), 40); 53 | expect(DateTime(2023, 1, 31).adjustedWeekOfYear(DateTime.sunday), 5); 54 | expect(DateTime(2023, 4, 30).adjustedWeekOfYear(DateTime.sunday), 18); 55 | expect(DateTime(2023, 7, 31).adjustedWeekOfYear(DateTime.sunday), 31); 56 | expect(DateTime(2023, 10, 31).adjustedWeekOfYear(DateTime.sunday), 44); 57 | expect(DateTime(2023, 2, 29).adjustedWeekOfYear(DateTime.sunday), 9); // 1.3. 58 | }); 59 | test('Week of the year: Week starts with Wednesday', () { //checked with noteplan 60 | expect(DateTime(2023, 1, 1).adjustedWeekOfYear(DateTime.wednesday), 53); 61 | expect(DateTime(2023, 4, 1).adjustedWeekOfYear(DateTime.wednesday), 13); 62 | expect(DateTime(2023, 7, 1).adjustedWeekOfYear(DateTime.wednesday), 26); 63 | expect(DateTime(2023, 10, 1).adjustedWeekOfYear(DateTime.wednesday), 39); 64 | expect(DateTime(2023, 1, 31).adjustedWeekOfYear(DateTime.wednesday), 4); 65 | expect(DateTime(2023, 4, 30).adjustedWeekOfYear(DateTime.wednesday), 17); 66 | expect(DateTime(2023, 7, 31).adjustedWeekOfYear(DateTime.wednesday), 30); 67 | expect(DateTime(2023, 10, 31).adjustedWeekOfYear(DateTime.wednesday), 43); 68 | expect(DateTime(2023, 2, 29).adjustedWeekOfYear(DateTime.wednesday), 9); // 1.3. 69 | }); 70 | test('Quarter', () { 71 | expect(DateTime(2023, 1, 1).quarter, 1); 72 | expect(DateTime(2023, 4, 1).quarter, 2); 73 | expect(DateTime(2023, 7, 1).quarter, 3); 74 | expect(DateTime(2023, 10, 1).quarter, 4); 75 | expect(DateTime(2023, 1, 31).quarter, 1); 76 | expect(DateTime(2023, 4, 30).quarter, 2); 77 | expect(DateTime(2023, 7, 31).quarter, 3); 78 | expect(DateTime(2023, 10, 31).quarter, 4); 79 | expect(DateTime(2023, 2, 29).quarter, 1); //1.3 80 | expect(DateTime(2023, 3, 38).quarter, 2); //7.4 81 | }); 82 | }); 83 | 84 | group('Tuple date movement', () { 85 | test('Fails for weekly', () { 86 | (NoteType, int, int) t = (NoteType.weekly, 2023, 1); 87 | expect(() => t.shift(10), throwsStateError); 88 | expect(() => t.shift(-10), throwsStateError); 89 | expect(() => t.shift(0), throwsStateError); 90 | }); 91 | test('Monthly', () { 92 | (NoteType, int, int) t = (NoteType.monthly, 2023, 1); 93 | expect(t.shift(5).$3, 6); 94 | 95 | expect(t.shift(12).$3, 1); 96 | expect(t.shift(12).$2, 2024); 97 | 98 | expect(t.shift(-2).$3, 11); 99 | expect(t.shift(-2).$2, 2022); 100 | 101 | expect(t.shift(-23).$3, 2); 102 | expect(t.shift(-23).$2, 2021); 103 | }); 104 | 105 | test('Quarterly', () { 106 | (NoteType, int, int) t = (NoteType.quarterly, 2023, 1); 107 | expect(t.shift(5).$3, 2); 108 | 109 | expect(t.shift(12).$3, 1); 110 | expect(t.shift(12).$2, 2026); 111 | 112 | expect(t.shift(-2).$3, 3); 113 | expect(t.shift(-2).$2, 2022); 114 | 115 | expect(t.shift(-23).$3, 2); 116 | expect(t.shift(-23).$2, 2017); 117 | }); 118 | 119 | test('Yearly', () { 120 | (NoteType, int, int) t = (NoteType.yearly, 2023, 1); 121 | expect(t.shift(5).$2, 2028); 122 | 123 | expect(t.shift(12).$3, 1); 124 | expect(t.shift(12).$2, 2035); 125 | 126 | expect(t.shift(-2).$3, 1); 127 | expect(t.shift(-2).$2, 2021); 128 | 129 | expect(t.shift(-23).$3, 1); 130 | expect(t.shift(-23).$2, 2000); 131 | }); 132 | }); 133 | 134 | group('Noteplan naming + movement >', () { 135 | DateTime now = DateTime(2023, 1, 11); 136 | 137 | test('Fails correctly', () { 138 | expect(() => (NoteType.note, 2023, 1).toNoteplanDateString(), throwsArgumentError); 139 | expect(() => (NoteType.daily, 2023, 1).toNoteplanDateString(), throwsArgumentError); 140 | expect(() => now.toNoteplanDateString(NoteType.note), throwsArgumentError); 141 | }); 142 | 143 | DateTime dt; 144 | test('Daily', () { 145 | expect(now.toNoteplanDateString(NoteType.daily), '20230111'); 146 | dt = now.add(Duration(days: -20)); 147 | expect(dt.toNoteplanDateString(NoteType.daily), '20221222'); 148 | dt = now.add(Duration(days: -200)); 149 | expect(dt.toNoteplanDateString(NoteType.daily), '20220625'); 150 | dt = now.add(Duration(days: 20)); 151 | expect(dt.toNoteplanDateString(NoteType.daily), '20230131'); 152 | dt = now.add(Duration(days: 21)); 153 | expect(dt.toNoteplanDateString(NoteType.daily), '20230201'); 154 | dt = now.add(Duration(days: 200)); 155 | expect(dt.toNoteplanDateString(NoteType.daily), '20230730'); 156 | }); 157 | test('Weekly (Monday)', () { 158 | expect(now.toNoteplanDateString(NoteType.weekly),'2023-W02'); 159 | dt = now.add(Duration(days: -20 * 7)); 160 | expect(dt.toNoteplanDateString(NoteType.weekly), '2022-W34'); 161 | dt = now.add(Duration(days: -47 * 7)); 162 | expect(dt.toNoteplanDateString(NoteType.weekly), '2022-W07'); 163 | dt = now.add(Duration(days: 20 * 7)); 164 | expect(dt.toNoteplanDateString(NoteType.weekly), '2023-W22'); 165 | dt = now.add(Duration(days: 21 * 7)); 166 | expect(dt.toNoteplanDateString(NoteType.weekly), '2023-W23'); 167 | dt = now.add(Duration(days: 67 * 7)); 168 | expect(dt.toNoteplanDateString(NoteType.weekly), '2024-W17'); 169 | }); 170 | test('Weekly (Sunday)', () { 171 | Config.week_starts_on = 7; // US weirdos 172 | expect(now.toNoteplanDateString(NoteType.weekly),'2023-W02'); 173 | dt = now.add(Duration(days: -20 * 7)); 174 | expect(dt.toNoteplanDateString(NoteType.weekly), '2022-W34'); 175 | dt = now.add(Duration(days: -47 * 7)); 176 | expect(dt.toNoteplanDateString(NoteType.weekly), '2022-W07'); 177 | dt = now.add(Duration(days: 20 * 7)); 178 | expect(dt.toNoteplanDateString(NoteType.weekly), '2023-W22'); 179 | dt = now.add(Duration(days: 21 * 7)); 180 | expect(dt.toNoteplanDateString(NoteType.weekly), '2023-W23'); 181 | dt = now.add(Duration(days: 67 * 7)); 182 | expect(dt.toNoteplanDateString(NoteType.weekly), '2024-W17'); 183 | }); 184 | test('Monthly', () { 185 | expect(now.toNoteplanDateString(NoteType.monthly),'2023-01'); 186 | dt = DateTime(now.year, now.month + -20, 1); 187 | expect(dt.toNoteplanDateString(NoteType.monthly), '2021-05'); 188 | dt = DateTime(now.year, now.month + -200, 1); 189 | expect(dt.toNoteplanDateString(NoteType.monthly), '2006-05'); 190 | dt = DateTime(now.year, now.month + 20, 1); 191 | expect(dt.toNoteplanDateString(NoteType.monthly), '2024-09'); 192 | dt = DateTime(now.year, now.month + 21, 1); 193 | expect(dt.toNoteplanDateString(NoteType.monthly), '2024-10'); 194 | dt = DateTime(now.year, now.month + 200, 1); 195 | expect(dt.toNoteplanDateString(NoteType.monthly), '2039-09'); 196 | }); 197 | test('Quarterly', () { 198 | expect(now.toNoteplanDateString(NoteType.quarterly), '2023-Q1'); 199 | dt = DateTime(now.year, now.month + 3 * 2, 1); 200 | expect(dt.toNoteplanDateString(NoteType.quarterly), '2023-Q3'); 201 | dt = DateTime(now.year, now.month + 3 * -2, 1); 202 | expect(dt.toNoteplanDateString(NoteType.quarterly), '2022-Q3'); 203 | dt = DateTime(now.year, now.month + 3 * 20, 1); 204 | expect(dt.toNoteplanDateString(NoteType.quarterly), '2028-Q1'); 205 | dt = DateTime(now.year, now.month + 3 * -20, 1); 206 | expect(dt.toNoteplanDateString(NoteType.quarterly), '2018-Q1'); 207 | }); 208 | test('Yearly', () { 209 | expect(now.toNoteplanDateString(NoteType.yearly), '2023'); 210 | dt = DateTime(now.year + 2, now.month, 1); 211 | expect(dt.toNoteplanDateString(NoteType.yearly), '2025'); 212 | dt = DateTime(now.year - 2, now.month, 1); 213 | expect(dt.toNoteplanDateString(NoteType.yearly), '2021'); 214 | dt = DateTime(now.year - 2020, now.month, 1); 215 | expect(dt.toNoteplanDateString(NoteType.yearly), '0003'); 216 | }); 217 | }); 218 | } -------------------------------------------------------------------------------- /test/fake-run.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env zsh 2 | # shellcheck shell=bash 3 | 4 | cd workflow || exit 1 # imitate CWD to workflow 5 | 6 | # shellcheck disable=SC1091 7 | source ../test/workflow-search-all.sh -------------------------------------------------------------------------------- /test/note_test.dart: -------------------------------------------------------------------------------- 1 | import 'package:alfred_noteplan/note.dart'; 2 | import 'package:alfred_noteplan/strings.dart'; 3 | import 'package:test/test.dart'; 4 | 5 | void main() { 6 | final Note emptyNote = Note( 7 | 'example/folder/Note.md', 8 | ''' 9 | '''.unindent(), 10 | DateTime.now().millisecondsSinceEpoch, 11 | 1 // default note 12 | ); 13 | 14 | test("Empty note", () { 15 | expect(emptyNote.hyperlinks.isEmpty, true); 16 | expect(emptyNote.code_bits.isEmpty, true); 17 | expect(emptyNote.title, "Note"); 18 | }); 19 | 20 | /// /// /// /// /// 21 | 22 | final Note pureNote = Note( 23 | 'example/markdown/Note with pure Markdown.md', 24 | ''' 25 | # This is the title 26 | 27 | - item 1 28 | - item 2 29 | - item 3 30 | 31 | ## Shop for these 32 | 33 | * Cookies 34 | * Bread 35 | * Don't forget to pick up milk (!) 36 | '''.unindent(), 37 | DateTime.now().millisecondsSinceEpoch, 38 | 1 39 | ); 40 | 41 | test("Note without frontmatter", () { 42 | expect(pureNote.hyperlinks.isEmpty, true); 43 | expect(pureNote.code_bits.isEmpty, true); 44 | expect(pureNote.title, "This is the title"); 45 | expect(pureNote.content, """ 46 | - item 1 47 | - item 2 48 | - item 3 49 | 50 | ## Shop for these 51 | 52 | * Cookies 53 | * Bread 54 | * Don't forget to pick up milk (!) 55 | """.unindent().cleanForFts()); 56 | }); 57 | 58 | /// /// /// /// /// 59 | 60 | final Note noteWithFM = Note( 61 | 'example/markdown/Note with Frontmatter.md', 62 | ''' 63 | --- 64 | title: I am r/verysmart 65 | tags: yes, sometimes 66 | --- 67 | 68 | ## Subheading 69 | 70 | - [Very cool website](https://adamkiss.com) 71 | - [This workflow](https://github.com/adamkiss/alfred-noteplan) 72 | - [The Witcher is a book you should read](https://en.wikipedia.org/wiki/The_Witcher) 73 | 74 | ## These are ignored 75 | - [Link to a note with custom title]([[A cool note]]) 76 | - [file](Note_attachmends/Amazing File.mp4) 77 | 78 | ## Shop for these 79 | 80 | * Cookies 81 | * Bread 82 | * Don't forget to pick up milk (!) 83 | '''.unindent(), 84 | DateTime.now().millisecondsSinceEpoch, 85 | 1 86 | ); 87 | 88 | test("Note with a frontmatter", () { 89 | expect(noteWithFM.title, "I am r/verysmart"); 90 | expect(noteWithFM.code_bits.isEmpty, true); 91 | expect(noteWithFM.hyperlinks.isNotEmpty, true); 92 | 93 | expect(noteWithFM.hyperlinks.length, 3); 94 | expect(noteWithFM.hyperlinks[0].url, 'https://adamkiss.com'); 95 | expect(noteWithFM.hyperlinks[0].title, 'Very cool website'); 96 | expect(noteWithFM.hyperlinks[0].description, null); 97 | 98 | expect(noteWithFM.hyperlinks[1].url, 'https://github.com/adamkiss/alfred-noteplan'); 99 | expect(noteWithFM.hyperlinks[1].title, 'This workflow'); 100 | expect(noteWithFM.hyperlinks[1].description, null); 101 | 102 | expect(noteWithFM.hyperlinks[2].url, 'https://en.wikipedia.org/wiki/The_Witcher'); 103 | expect(noteWithFM.hyperlinks[2].title, 'The Witcher is a book you should read'); 104 | expect(noteWithFM.hyperlinks[2].description, null); 105 | }); 106 | 107 | /// /// /// /// /// 108 | 109 | final Note noteWithCode = Note( 110 | 'example/markdown/Note with quite a bit of code.md', 111 | ''' 112 | --- 113 | title: I was writing these all night 114 | --- 115 | 116 | ## Something without title or language (ignored) 117 | 118 | ``` 119 | <?php 120 | 121 | app()->route('/hyperlinks/(:any)', fn(string \$id) => new Route(\$id)); 122 | ``` 123 | 124 | ## Language only (ignored) 125 | 126 | ```js 127 | document.addEventListener('click', () => console.log('Arrow fns are cool!')); 128 | ``` 129 | 130 | ## This time with title 131 | 132 | ```dart (Enum of my stupidity) 133 | Enum AlfredNoteplan2 { 134 | javascript, 135 | php, 136 | dart; 137 | } 138 | ``` 139 | 140 | ## I was talkative this time 141 | 142 | ```swift (I still don't understand - And people call it "elegant"?) 143 | @_functionBuilder 144 | struct NodeBuilder { 145 | static func buildBlock<Value>(_ children: Node<Value>...) -> [Node<Value>] { 146 | children 147 | } 148 | } 149 | ``` 150 | 151 | '''.unindent(), 152 | DateTime.now().millisecondsSinceEpoch, 153 | 1 154 | ); 155 | 156 | test("Note with a lot of code", () { 157 | expect(noteWithCode.title, "I was writing these all night"); 158 | expect(noteWithCode.hyperlinks.isEmpty, true); 159 | expect(noteWithCode.code_bits.isNotEmpty, true); 160 | 161 | expect(noteWithCode.code_bits.length, 2); 162 | expect(noteWithCode.code_bits[0].language, 'dart'); 163 | expect(noteWithCode.code_bits[0].title, 'Enum of my stupidity'); 164 | expect(noteWithCode.code_bits[1].language, 'swift'); 165 | expect(noteWithCode.code_bits[1].title, 'I still don\'t understand - And people call it "elegant"?'); 166 | }); 167 | } -------------------------------------------------------------------------------- /test/strings_test.dart: -------------------------------------------------------------------------------- 1 | import 'package:alfred_noteplan/strings.dart'; 2 | import 'package:test/test.dart'; 3 | 4 | void main() { 5 | String edgy = "ThiS iS vEry edGY!"; 6 | test('Capitalized (sentence) case', () { 7 | expect(edgy.toCapitalized(), "This is very edgy!"); 8 | }); 9 | test('Title case', () { 10 | expect(edgy.toTitleCase(), "This Is Very Edgy!"); 11 | }); 12 | test('Split format and capitalize', (){ 13 | // noop 14 | }); 15 | 16 | String markdown = ''' 17 | # Header 1 18 | 19 | - item 1 20 | - item 2 21 | - item 3 22 | 23 | * item 1 24 | * item 2 25 | * **bold item 3** 26 | '''; 27 | test("Unindent", () { 28 | expect(markdown.unindent(), ''' 29 | # Header 1 30 | 31 | - item 1 32 | - item 2 33 | - item 3 34 | 35 | * item 1 36 | * item 2 37 | * **bold item 3** 38 | '''); 39 | }); 40 | 41 | 42 | test("FTS Cleaning", () { 43 | expect(markdown.unindent().cleanForFts(), '''Header 1 44 | item 1 45 | item 2 46 | item 3 47 | item 1 48 | item 2 49 | bold item 3'''); 50 | }); 51 | } 52 | -------------------------------------------------------------------------------- /test/test.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env zsh 2 | # shellcheck shell=bash 3 | 4 | # rebuild 5 | ./r.sh build:dart 6 | 7 | # set test env variables 8 | user_np_root='/Users/adam/Library/Containers/co.noteplan.NotePlan-setapp/Data/Library/Application Support/co.noteplan.NotePlan-setapp' 9 | user_new_note_template="---\ntitle: TITLE\n---\n\n" 10 | 11 | # CWD is the root 12 | echo "RETURN HELP OPTIONS (outputs: 3)" 13 | user_np_root=$user_np_root user_new_note_template=$user_new_note_template \ 14 | zsh test/fake-run.sh ! | jq '.items | length' 15 | echo 16 | 17 | echo "SHOW DEBUG INFORMATION" 18 | user_np_root=$user_np_root user_new_note_template=$user_new_note_template \ 19 | zsh test/fake-run.sh !! | jq -r '.items | map(.subtitle + ": " +.title)' 20 | echo 21 | 22 | echo "FORCE REFRESH" 23 | user_np_root=$user_np_root user_new_note_template=$user_new_note_template \ 24 | zsh test/fake-run.sh !rf | jq -r '.items[0].title' 25 | echo 26 | 27 | echo "REFRESH CHANGED (nothing)" 28 | user_np_root=$user_np_root user_new_note_template=$user_new_note_template \ 29 | zsh test/fake-run.sh !r | jq -r '.items[0].title' 30 | echo 31 | 32 | echo "CREATE NOTE - folders" 33 | user_np_root=$user_np_root user_new_note_template=$user_new_note_template \ 34 | ./workflow/noteplan-arm64 create 'Ahoy there captain!' | jq -r '.items | map(.title + ": "+ .arg)' 35 | echo 36 | 37 | echo "SEARCH - adam kiss (outputs: 19 [18 + create])" 38 | user_np_root=$user_np_root user_new_note_template=$user_new_note_template \ 39 | ./workflow/noteplan-arm64 search 'adam kiss' | jq '.items | map(.title + " - " + .subtitle)' 40 | echo 41 | 42 | echo "Bookmark search - kirby" 43 | user_np_root=$user_np_root user_new_note_template=$user_new_note_template \ 44 | ./workflow/noteplan-arm64 hyperlinks 'kirby' | jq '.items | map(.title + " - " + .subtitle)' 45 | echo 46 | 47 | echo "Code bit search - php" 48 | user_np_root=$user_np_root user_new_note_template=$user_new_note_template \ 49 | ./workflow/noteplan-arm64 code_bits 'php' | jq '.items | map(.title + " - " + .subtitle)' 50 | echo 51 | 52 | echo "Code bit search - go" 53 | user_np_root=$user_np_root user_new_note_template=$user_new_note_template \ 54 | ./workflow/noteplan-arm64 code_bits 'go' | jq '.items | map(.title + " - " + .subtitle)' 55 | echo 56 | 57 | echo "All search - kirby" 58 | user_np_root=$user_np_root user_new_note_template=$user_new_note_template \ 59 | ./workflow/noteplan-arm64 all 'kirby' | jq '.items | map(.title + " - " + .subtitle)' 60 | echo -------------------------------------------------------------------------------- /test/workflow-date.sh: -------------------------------------------------------------------------------- 1 | # shellcheck disable=SC2148 2 | BIN="./noteplan-$(uname -m)" 3 | 4 | function info { 5 | cat <<- JSON 6 | {"items": [ 7 | { 8 | "title": "!! - Debug", 9 | "subtitle": "Show & copy debugging information (versions, architecture)", 10 | "valid": false, 11 | "autocomplete": "!!" 12 | }, 13 | { 14 | "title": "!r - Refresh", 15 | "subtitle": "Refresh the database (since the last update)", 16 | "valid": false, 17 | "autocomplete": "!r" 18 | }, 19 | { 20 | "title": "!rf - Refresh (Force)", 21 | "subtitle": "Force full refresh of the database", 22 | "valid": false, 23 | "autocomplete": "!rf" 24 | } 25 | ]} 26 | JSON 27 | } 28 | 29 | case "$1" in 30 | "!") 31 | info 32 | ;; 33 | "!!") 34 | $BIN debug 35 | ;; 36 | "!r") 37 | $BIN refresh 38 | ;; 39 | "!rf") 40 | $BIN refresh force 41 | ;; 42 | *) 43 | $BIN date "$1" 44 | ;; 45 | esac 46 | -------------------------------------------------------------------------------- /test/workflow-search-all.sh: -------------------------------------------------------------------------------- 1 | # shellcheck disable=SC2148 2 | BIN="./noteplan-$(uname -m)" 3 | 4 | function info { 5 | cat <<- JSON 6 | {"items": [ 7 | { 8 | "title": "!! - Debug", 9 | "subtitle": "Show & copy debugging information (versions, architecture)", 10 | "valid": false, 11 | "autocomplete": "!!" 12 | }, 13 | { 14 | "title": "!r - Refresh", 15 | "subtitle": "Refresh the database (since the last update)", 16 | "valid": false, 17 | "autocomplete": "!r" 18 | }, 19 | { 20 | "title": "!rf - Refresh (Force)", 21 | "subtitle": "Force full refresh of the database", 22 | "valid": false, 23 | "autocomplete": "!rf" 24 | } 25 | ]} 26 | JSON 27 | } 28 | 29 | case "$1" in 30 | "!") 31 | info 32 | ;; 33 | "!!") 34 | $BIN debug 35 | ;; 36 | "!r") 37 | $BIN refresh 38 | ;; 39 | "!rf") 40 | $BIN refresh force 41 | ;; 42 | *) 43 | $BIN all "$1" 44 | ;; 45 | esac 46 | -------------------------------------------------------------------------------- /test/workflow-search-code-bits.sh: -------------------------------------------------------------------------------- 1 | # shellcheck disable=SC2148 2 | BIN="./noteplan-$(uname -m)" 3 | $BIN code_bits "$1" -------------------------------------------------------------------------------- /test/workflow-search-hyperlinks.sh: -------------------------------------------------------------------------------- 1 | # shellcheck disable=SC2148 2 | BIN="./noteplan-$(uname -m)" 3 | $BIN hyperlinks "$1" -------------------------------------------------------------------------------- /test/workflow-search-notes.sh: -------------------------------------------------------------------------------- 1 | # shellcheck disable=SC2148 2 | BIN="./noteplan-$(uname -m)" 3 | 4 | function info { 5 | cat <<- JSON 6 | {"items": [ 7 | { 8 | "title": "!! - Debug", 9 | "subtitle": "Show & copy debugging information (versions, architecture)", 10 | "valid": false, 11 | "autocomplete": "!!" 12 | }, 13 | { 14 | "title": "!r - Refresh", 15 | "subtitle": "Refresh the database (since the last update)", 16 | "valid": false, 17 | "autocomplete": "!r" 18 | }, 19 | { 20 | "title": "!rf - Refresh (Force)", 21 | "subtitle": "Force full refresh of the database", 22 | "valid": false, 23 | "autocomplete": "!rf" 24 | } 25 | ]} 26 | JSON 27 | } 28 | 29 | case "$1" in 30 | "!") 31 | info 32 | ;; 33 | "!!") 34 | $BIN debug 35 | ;; 36 | "!r") 37 | $BIN refresh 38 | ;; 39 | "!rf") 40 | $BIN refresh force 41 | ;; 42 | *) 43 | $BIN search "$1" 44 | ;; 45 | esac 46 | -------------------------------------------------------------------------------- /workflow/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adamkiss/alfred-noteplan/c8689c4779216c31628b797777b863e302ba4500/workflow/icon.png -------------------------------------------------------------------------------- /workflow/icons/icon-code-bit.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adamkiss/alfred-noteplan/c8689c4779216c31628b797777b863e302ba4500/workflow/icons/icon-code-bit.icns -------------------------------------------------------------------------------- /workflow/icons/icon-create.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adamkiss/alfred-noteplan/c8689c4779216c31628b797777b863e302ba4500/workflow/icons/icon-create.icns -------------------------------------------------------------------------------- /workflow/icons/icon-daily.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adamkiss/alfred-noteplan/c8689c4779216c31628b797777b863e302ba4500/workflow/icons/icon-daily.icns -------------------------------------------------------------------------------- /workflow/icons/icon-folder.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adamkiss/alfred-noteplan/c8689c4779216c31628b797777b863e302ba4500/workflow/icons/icon-folder.icns -------------------------------------------------------------------------------- /workflow/icons/icon-hyperlink.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adamkiss/alfred-noteplan/c8689c4779216c31628b797777b863e302ba4500/workflow/icons/icon-hyperlink.icns -------------------------------------------------------------------------------- /workflow/icons/icon-monthly.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adamkiss/alfred-noteplan/c8689c4779216c31628b797777b863e302ba4500/workflow/icons/icon-monthly.icns -------------------------------------------------------------------------------- /workflow/icons/icon-note.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adamkiss/alfred-noteplan/c8689c4779216c31628b797777b863e302ba4500/workflow/icons/icon-note.icns -------------------------------------------------------------------------------- /workflow/icons/icon-quarterly.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adamkiss/alfred-noteplan/c8689c4779216c31628b797777b863e302ba4500/workflow/icons/icon-quarterly.icns -------------------------------------------------------------------------------- /workflow/icons/icon-weekly.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adamkiss/alfred-noteplan/c8689c4779216c31628b797777b863e302ba4500/workflow/icons/icon-weekly.icns -------------------------------------------------------------------------------- /workflow/icons/icon-yearly.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adamkiss/alfred-noteplan/c8689c4779216c31628b797777b863e302ba4500/workflow/icons/icon-yearly.icns -------------------------------------------------------------------------------- /workflow/info.plist: -------------------------------------------------------------------------------- 1 | <?xml version="1.0" encoding="UTF-8"?> 2 | <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> 3 | <plist version="1.0"> 4 | <dict> 5 | <key>bundleid</key> 6 | <string>com.adamkiss.alfred-noteplan-dart</string> 7 | <key>category</key> 8 | <string>Apps Control</string> 9 | <key>connections</key> 10 | <dict> 11 | <key>053FDDB4-A265-4274-8F91-1BE7C16BC397</key> 12 | <array> 13 | <dict> 14 | <key>destinationuid</key> 15 | <string>748CC6DD-431D-47CA-B2A7-F54387FE69FC</string> 16 | <key>modifiers</key> 17 | <integer>0</integer> 18 | <key>modifiersubtext</key> 19 | <string></string> 20 | <key>vitoclose</key> 21 | <false/> 22 | </dict> 23 | </array> 24 | <key>0F615941-D8B5-4106-A152-607F8FB1F4CD</key> 25 | <array> 26 | <dict> 27 | <key>destinationuid</key> 28 | <string>748CC6DD-431D-47CA-B2A7-F54387FE69FC</string> 29 | <key>modifiers</key> 30 | <integer>0</integer> 31 | <key>modifiersubtext</key> 32 | <string></string> 33 | <key>vitoclose</key> 34 | <false/> 35 | </dict> 36 | </array> 37 | <key>32184673-6E45-4E1E-A9A3-5E277249F059</key> 38 | <array> 39 | <dict> 40 | <key>destinationuid</key> 41 | <string>E7234EA6-7AE9-4354-9CEC-95A19238A3FC</string> 42 | <key>modifiers</key> 43 | <integer>0</integer> 44 | <key>modifiersubtext</key> 45 | <string></string> 46 | <key>vitoclose</key> 47 | <false/> 48 | </dict> 49 | </array> 50 | <key>583FB278-5756-4AC2-A2BB-EA55CED6B10F</key> 51 | <array> 52 | <dict> 53 | <key>destinationuid</key> 54 | <string>5D0CA85B-D6F6-4677-9559-11AFA08F01BC</string> 55 | <key>modifiers</key> 56 | <integer>0</integer> 57 | <key>modifiersubtext</key> 58 | <string></string> 59 | <key>vitoclose</key> 60 | <false/> 61 | </dict> 62 | </array> 63 | <key>5D0CA85B-D6F6-4677-9559-11AFA08F01BC</key> 64 | <array> 65 | <dict> 66 | <key>destinationuid</key> 67 | <string>32184673-6E45-4E1E-A9A3-5E277249F059</string> 68 | <key>modifiers</key> 69 | <integer>0</integer> 70 | <key>modifiersubtext</key> 71 | <string></string> 72 | <key>vitoclose</key> 73 | <false/> 74 | </dict> 75 | </array> 76 | <key>68DA41FC-6D2C-4123-A82E-D20D0A3BBA66</key> 77 | <array/> 78 | <key>748CC6DD-431D-47CA-B2A7-F54387FE69FC</key> 79 | <array> 80 | <dict> 81 | <key>destinationuid</key> 82 | <string>8CD51E99-89FA-439A-A640-C4174B1D5C01</string> 83 | <key>modifiers</key> 84 | <integer>0</integer> 85 | <key>modifiersubtext</key> 86 | <string></string> 87 | <key>sourceoutputuid</key> 88 | <string>FA26312F-4035-4B5D-A0AD-B1E785BCC8F6</string> 89 | <key>vitoclose</key> 90 | <false/> 91 | </dict> 92 | <dict> 93 | <key>destinationuid</key> 94 | <string>876A2F3F-9B6C-4253-92BA-D005783257A9</string> 95 | <key>modifiers</key> 96 | <integer>0</integer> 97 | <key>modifiersubtext</key> 98 | <string></string> 99 | <key>sourceoutputuid</key> 100 | <string>4DA7BF5A-5614-44DF-8ADE-C4C03242D0D9</string> 101 | <key>vitoclose</key> 102 | <false/> 103 | </dict> 104 | <dict> 105 | <key>destinationuid</key> 106 | <string>E7234EA6-7AE9-4354-9CEC-95A19238A3FC</string> 107 | <key>modifiers</key> 108 | <integer>0</integer> 109 | <key>modifiersubtext</key> 110 | <string></string> 111 | <key>sourceoutputuid</key> 112 | <string>649661E6-0AF9-41D7-AB20-6549D3B1095B</string> 113 | <key>vitoclose</key> 114 | <false/> 115 | </dict> 116 | <dict> 117 | <key>destinationuid</key> 118 | <string>68DA41FC-6D2C-4123-A82E-D20D0A3BBA66</string> 119 | <key>modifiers</key> 120 | <integer>0</integer> 121 | <key>modifiersubtext</key> 122 | <string></string> 123 | <key>sourceoutputuid</key> 124 | <string>CCC4816B-5B6A-4259-A5D4-019CE258611D</string> 125 | <key>vitoclose</key> 126 | <false/> 127 | </dict> 128 | <dict> 129 | <key>destinationuid</key> 130 | <string>5D0CA85B-D6F6-4677-9559-11AFA08F01BC</string> 131 | <key>modifiers</key> 132 | <integer>0</integer> 133 | <key>modifiersubtext</key> 134 | <string></string> 135 | <key>vitoclose</key> 136 | <false/> 137 | </dict> 138 | </array> 139 | <key>98B6F5C9-30A7-49D0-813C-ECF85C399CCA</key> 140 | <array> 141 | <dict> 142 | <key>destinationuid</key> 143 | <string>748CC6DD-431D-47CA-B2A7-F54387FE69FC</string> 144 | <key>modifiers</key> 145 | <integer>0</integer> 146 | <key>modifiersubtext</key> 147 | <string></string> 148 | <key>vitoclose</key> 149 | <false/> 150 | </dict> 151 | </array> 152 | <key>E620799B-C916-42D7-87BE-B5AD280F147D</key> 153 | <array> 154 | <dict> 155 | <key>destinationuid</key> 156 | <string>748CC6DD-431D-47CA-B2A7-F54387FE69FC</string> 157 | <key>modifiers</key> 158 | <integer>0</integer> 159 | <key>modifiersubtext</key> 160 | <string></string> 161 | <key>vitoclose</key> 162 | <false/> 163 | </dict> 164 | </array> 165 | </dict> 166 | <key>createdby</key> 167 | <string>Adam Kiss</string> 168 | <key>description</key> 169 | <string>Full text search for Noteplan, shortcuts for note creation, and other useful Noteplan stuff</string> 170 | <key>disabled</key> 171 | <false/> 172 | <key>name</key> 173 | <string>Noteplan</string> 174 | <key>objects</key> 175 | <array> 176 | <dict> 177 | <key>config</key> 178 | <dict> 179 | <key>autopaste</key> 180 | <false/> 181 | <key>clipboardtext</key> 182 | <string>{query}</string> 183 | <key>ignoredynamicplaceholders</key> 184 | <false/> 185 | <key>transient</key> 186 | <false/> 187 | </dict> 188 | <key>type</key> 189 | <string>alfred.workflow.output.clipboard</string> 190 | <key>uid</key> 191 | <string>8CD51E99-89FA-439A-A640-C4174B1D5C01</string> 192 | <key>version</key> 193 | <integer>3</integer> 194 | </dict> 195 | <dict> 196 | <key>config</key> 197 | <dict> 198 | <key>alfredfiltersresults</key> 199 | <false/> 200 | <key>alfredfiltersresultsmatchmode</key> 201 | <integer>0</integer> 202 | <key>argumenttreatemptyqueryasnil</key> 203 | <true/> 204 | <key>argumenttrimmode</key> 205 | <integer>0</integer> 206 | <key>argumenttype</key> 207 | <integer>0</integer> 208 | <key>escaping</key> 209 | <integer>102</integer> 210 | <key>keyword</key> 211 | <string>{var:workflow_trigger_open}</string> 212 | <key>queuedelaycustom</key> 213 | <integer>3</integer> 214 | <key>queuedelayimmediatelyinitially</key> 215 | <true/> 216 | <key>queuedelaymode</key> 217 | <integer>0</integer> 218 | <key>queuemode</key> 219 | <integer>1</integer> 220 | <key>runningsubtext</key> 221 | <string>Looking for {query}</string> 222 | <key>script</key> 223 | <string># shellcheck disable=SC2148 224 | BIN="./noteplan-$(uname -m)" 225 | 226 | function info { 227 | cat <<- JSON 228 | {"items": [ 229 | { 230 | "title": "!! - Debug", 231 | "subtitle": "Show & copy debugging information (versions, architecture)", 232 | "valid": false, 233 | "autocomplete": "!!" 234 | }, 235 | { 236 | "title": "!r - Refresh", 237 | "subtitle": "Refresh the database (since the last update)", 238 | "valid": false, 239 | "autocomplete": "!r" 240 | }, 241 | { 242 | "title": "!rf - Refresh (Force)", 243 | "subtitle": "Force full refresh of the database", 244 | "valid": false, 245 | "autocomplete": "!rf" 246 | } 247 | ]} 248 | JSON 249 | } 250 | 251 | case "$1" in 252 | "!") 253 | info 254 | ;; 255 | "!!") 256 | $BIN debug 257 | ;; 258 | "!r") 259 | $BIN refresh 260 | ;; 261 | "!rf") 262 | $BIN refresh force 263 | ;; 264 | *) 265 | $BIN all "$1" 266 | ;; 267 | esac</string> 268 | <key>scriptargtype</key> 269 | <integer>1</integer> 270 | <key>scriptfile</key> 271 | <string></string> 272 | <key>subtext</key> 273 | <string>Full-text search for Noteplan</string> 274 | <key>title</key> 275 | <string>Noteplan FTS</string> 276 | <key>type</key> 277 | <integer>5</integer> 278 | <key>withspace</key> 279 | <true/> 280 | </dict> 281 | <key>type</key> 282 | <string>alfred.workflow.input.scriptfilter</string> 283 | <key>uid</key> 284 | <string>053FDDB4-A265-4274-8F91-1BE7C16BC397</string> 285 | <key>version</key> 286 | <integer>3</integer> 287 | </dict> 288 | <dict> 289 | <key>config</key> 290 | <dict> 291 | <key>autopaste</key> 292 | <true/> 293 | <key>clipboardtext</key> 294 | <string>{query}</string> 295 | <key>ignoredynamicplaceholders</key> 296 | <false/> 297 | <key>transient</key> 298 | <false/> 299 | </dict> 300 | <key>type</key> 301 | <string>alfred.workflow.output.clipboard</string> 302 | <key>uid</key> 303 | <string>876A2F3F-9B6C-4253-92BA-D005783257A9</string> 304 | <key>version</key> 305 | <integer>3</integer> 306 | </dict> 307 | <dict> 308 | <key>config</key> 309 | <dict> 310 | <key>alfredfiltersresults</key> 311 | <false/> 312 | <key>alfredfiltersresultsmatchmode</key> 313 | <integer>0</integer> 314 | <key>argumenttreatemptyqueryasnil</key> 315 | <true/> 316 | <key>argumenttrimmode</key> 317 | <integer>0</integer> 318 | <key>argumenttype</key> 319 | <integer>0</integer> 320 | <key>escaping</key> 321 | <integer>102</integer> 322 | <key>keyword</key> 323 | <string>{var:workflow_trigger_date}</string> 324 | <key>queuedelaycustom</key> 325 | <integer>3</integer> 326 | <key>queuedelayimmediatelyinitially</key> 327 | <true/> 328 | <key>queuedelaymode</key> 329 | <integer>0</integer> 330 | <key>queuemode</key> 331 | <integer>1</integer> 332 | <key>runningsubtext</key> 333 | <string>Matching {query}</string> 334 | <key>script</key> 335 | <string># shellcheck disable=SC2148 336 | BIN="./noteplan-$(uname -m)" 337 | 338 | function info { 339 | cat <<- JSON 340 | {"items": [ 341 | { 342 | "title": "!! - Debug", 343 | "subtitle": "Show & copy debugging information (versions, architecture)", 344 | "valid": false, 345 | "autocomplete": "!!" 346 | }, 347 | { 348 | "title": "!r - Refresh", 349 | "subtitle": "Refresh the database (since the last update)", 350 | "valid": false, 351 | "autocomplete": "!r" 352 | }, 353 | { 354 | "title": "!rf - Refresh (Force)", 355 | "subtitle": "Force full refresh of the database", 356 | "valid": false, 357 | "autocomplete": "!rf" 358 | } 359 | ]} 360 | JSON 361 | } 362 | 363 | case "$1" in 364 | "!") 365 | info 366 | ;; 367 | "!!") 368 | $BIN debug 369 | ;; 370 | "!r") 371 | $BIN refresh 372 | ;; 373 | "!rf") 374 | $BIN refresh force 375 | ;; 376 | *) 377 | $BIN date "$1" 378 | ;; 379 | esac</string> 380 | <key>scriptargtype</key> 381 | <integer>1</integer> 382 | <key>scriptfile</key> 383 | <string></string> 384 | <key>subtext</key> 385 | <string>Opens exact Calendar note</string> 386 | <key>title</key> 387 | <string>Noteplan FTS: Exact note</string> 388 | <key>type</key> 389 | <integer>5</integer> 390 | <key>withspace</key> 391 | <true/> 392 | </dict> 393 | <key>type</key> 394 | <string>alfred.workflow.input.scriptfilter</string> 395 | <key>uid</key> 396 | <string>98B6F5C9-30A7-49D0-813C-ECF85C399CCA</string> 397 | <key>version</key> 398 | <integer>3</integer> 399 | </dict> 400 | <dict> 401 | <key>config</key> 402 | <dict> 403 | <key>conditions</key> 404 | <array> 405 | <dict> 406 | <key>inputstring</key> 407 | <string>{var:action}</string> 408 | <key>matchcasesensitive</key> 409 | <false/> 410 | <key>matchmode</key> 411 | <integer>0</integer> 412 | <key>matchstring</key> 413 | <string>copy-to-clipboard</string> 414 | <key>outputlabel</key> 415 | <string>Copy to Clipboard</string> 416 | <key>uid</key> 417 | <string>FA26312F-4035-4B5D-A0AD-B1E785BCC8F6</string> 418 | </dict> 419 | <dict> 420 | <key>inputstring</key> 421 | <string>{var:action}</string> 422 | <key>matchcasesensitive</key> 423 | <false/> 424 | <key>matchmode</key> 425 | <integer>0</integer> 426 | <key>matchstring</key> 427 | <string>copy-paste</string> 428 | <key>outputlabel</key> 429 | <string>Copy + Paste</string> 430 | <key>uid</key> 431 | <string>4DA7BF5A-5614-44DF-8ADE-C4C03242D0D9</string> 432 | </dict> 433 | <dict> 434 | <key>inputstring</key> 435 | <string>{var:action}</string> 436 | <key>matchcasesensitive</key> 437 | <false/> 438 | <key>matchmode</key> 439 | <integer>0</integer> 440 | <key>matchstring</key> 441 | <string>open</string> 442 | <key>outputlabel</key> 443 | <string>Open Browser</string> 444 | <key>uid</key> 445 | <string>649661E6-0AF9-41D7-AB20-6549D3B1095B</string> 446 | </dict> 447 | <dict> 448 | <key>inputstring</key> 449 | <string>{var:action}</string> 450 | <key>matchcasesensitive</key> 451 | <false/> 452 | <key>matchmode</key> 453 | <integer>0</integer> 454 | <key>matchstring</key> 455 | <string>close</string> 456 | <key>outputlabel</key> 457 | <string>Close Alfred</string> 458 | <key>uid</key> 459 | <string>CCC4816B-5B6A-4259-A5D4-019CE258611D</string> 460 | </dict> 461 | </array> 462 | <key>elselabel</key> 463 | <string>Create</string> 464 | <key>hideelse</key> 465 | <false/> 466 | </dict> 467 | <key>type</key> 468 | <string>alfred.workflow.utility.conditional</string> 469 | <key>uid</key> 470 | <string>748CC6DD-431D-47CA-B2A7-F54387FE69FC</string> 471 | <key>version</key> 472 | <integer>1</integer> 473 | </dict> 474 | <dict> 475 | <key>config</key> 476 | <dict> 477 | <key>browser</key> 478 | <string></string> 479 | <key>skipqueryencode</key> 480 | <false/> 481 | <key>skipvarencode</key> 482 | <false/> 483 | <key>spaces</key> 484 | <string></string> 485 | <key>url</key> 486 | <string></string> 487 | </dict> 488 | <key>type</key> 489 | <string>alfred.workflow.action.openurl</string> 490 | <key>uid</key> 491 | <string>E7234EA6-7AE9-4354-9CEC-95A19238A3FC</string> 492 | <key>version</key> 493 | <integer>1</integer> 494 | </dict> 495 | <dict> 496 | <key>config</key> 497 | <dict> 498 | <key>alfredfiltersresults</key> 499 | <false/> 500 | <key>alfredfiltersresultsmatchmode</key> 501 | <integer>0</integer> 502 | <key>argumenttreatemptyqueryasnil</key> 503 | <true/> 504 | <key>argumenttrimmode</key> 505 | <integer>0</integer> 506 | <key>argumenttype</key> 507 | <integer>0</integer> 508 | <key>escaping</key> 509 | <integer>102</integer> 510 | <key>keyword</key> 511 | <string>{var:workflow_trigger_hyperlinks}</string> 512 | <key>queuedelaycustom</key> 513 | <integer>3</integer> 514 | <key>queuedelayimmediatelyinitially</key> 515 | <true/> 516 | <key>queuedelaymode</key> 517 | <integer>0</integer> 518 | <key>queuemode</key> 519 | <integer>1</integer> 520 | <key>runningsubtext</key> 521 | <string>Matching {query}</string> 522 | <key>script</key> 523 | <string># shellcheck disable=SC2148 524 | BIN="./noteplan-$(uname -m)" 525 | $BIN hyperlinks "$1"</string> 526 | <key>scriptargtype</key> 527 | <integer>1</integer> 528 | <key>scriptfile</key> 529 | <string></string> 530 | <key>subtext</key> 531 | <string>Find a URL you've saved in your notes</string> 532 | <key>title</key> 533 | <string>Noteplan: Search hyperlinks</string> 534 | <key>type</key> 535 | <integer>5</integer> 536 | <key>withspace</key> 537 | <true/> 538 | </dict> 539 | <key>type</key> 540 | <string>alfred.workflow.input.scriptfilter</string> 541 | <key>uid</key> 542 | <string>E620799B-C916-42D7-87BE-B5AD280F147D</string> 543 | <key>version</key> 544 | <integer>3</integer> 545 | </dict> 546 | <dict> 547 | <key>type</key> 548 | <string>alfred.workflow.utility.hidealfred</string> 549 | <key>uid</key> 550 | <string>68DA41FC-6D2C-4123-A82E-D20D0A3BBA66</string> 551 | <key>version</key> 552 | <integer>1</integer> 553 | </dict> 554 | <dict> 555 | <key>config</key> 556 | <dict> 557 | <key>alfredfiltersresults</key> 558 | <false/> 559 | <key>alfredfiltersresultsmatchmode</key> 560 | <integer>0</integer> 561 | <key>argumenttreatemptyqueryasnil</key> 562 | <true/> 563 | <key>argumenttrimmode</key> 564 | <integer>0</integer> 565 | <key>argumenttype</key> 566 | <integer>0</integer> 567 | <key>escaping</key> 568 | <integer>102</integer> 569 | <key>keyword</key> 570 | <string>{var:workflow_trigger_code_bits}</string> 571 | <key>queuedelaycustom</key> 572 | <integer>3</integer> 573 | <key>queuedelayimmediatelyinitially</key> 574 | <true/> 575 | <key>queuedelaymode</key> 576 | <integer>0</integer> 577 | <key>queuemode</key> 578 | <integer>1</integer> 579 | <key>runningsubtext</key> 580 | <string>Matching {query}</string> 581 | <key>script</key> 582 | <string># shellcheck disable=SC2148 583 | BIN="./noteplan-$(uname -m)" 584 | $BIN code_bits "$1"</string> 585 | <key>scriptargtype</key> 586 | <integer>1</integer> 587 | <key>scriptfile</key> 588 | <string></string> 589 | <key>subtext</key> 590 | <string>Find and paste a code bit from your notes</string> 591 | <key>title</key> 592 | <string>Noteplan: Search code bits</string> 593 | <key>type</key> 594 | <integer>5</integer> 595 | <key>withspace</key> 596 | <true/> 597 | </dict> 598 | <key>type</key> 599 | <string>alfred.workflow.input.scriptfilter</string> 600 | <key>uid</key> 601 | <string>0F615941-D8B5-4106-A152-607F8FB1F4CD</string> 602 | <key>version</key> 603 | <integer>3</integer> 604 | </dict> 605 | <dict> 606 | <key>config</key> 607 | <dict> 608 | <key>argumenttype</key> 609 | <integer>0</integer> 610 | <key>keyword</key> 611 | <string>{var:workflow_trigger_new}</string> 612 | <key>subtext</key> 613 | <string>Create a new note ✱ You'll be asked for location in the next step</string> 614 | <key>text</key> 615 | <string>Create "{query}"</string> 616 | <key>withspace</key> 617 | <true/> 618 | </dict> 619 | <key>type</key> 620 | <string>alfred.workflow.input.keyword</string> 621 | <key>uid</key> 622 | <string>583FB278-5756-4AC2-A2BB-EA55CED6B10F</string> 623 | <key>version</key> 624 | <integer>1</integer> 625 | </dict> 626 | <dict> 627 | <key>config</key> 628 | <dict> 629 | <key>alfredfiltersresults</key> 630 | <true/> 631 | <key>alfredfiltersresultsmatchmode</key> 632 | <integer>2</integer> 633 | <key>argumenttreatemptyqueryasnil</key> 634 | <true/> 635 | <key>argumenttrimmode</key> 636 | <integer>0</integer> 637 | <key>argumenttype</key> 638 | <integer>2</integer> 639 | <key>escaping</key> 640 | <integer>102</integer> 641 | <key>keyword</key> 642 | <string>{var:title}</string> 643 | <key>queuedelaycustom</key> 644 | <integer>3</integer> 645 | <key>queuedelayimmediatelyinitially</key> 646 | <true/> 647 | <key>queuedelaymode</key> 648 | <integer>0</integer> 649 | <key>queuemode</key> 650 | <integer>1</integer> 651 | <key>runningsubtext</key> 652 | <string>Listing folders…</string> 653 | <key>script</key> 654 | <string>BIN="./noteplan-$(uname -m)" 655 | $BIN create "$title"</string> 656 | <key>scriptargtype</key> 657 | <integer>0</integer> 658 | <key>scriptfile</key> 659 | <string></string> 660 | <key>subtext</key> 661 | <string>Will create a new note in selected folder</string> 662 | <key>title</key> 663 | <string>Create note "{var:title}"</string> 664 | <key>type</key> 665 | <integer>0</integer> 666 | <key>withspace</key> 667 | <false/> 668 | </dict> 669 | <key>type</key> 670 | <string>alfred.workflow.input.scriptfilter</string> 671 | <key>uid</key> 672 | <string>32184673-6E45-4E1E-A9A3-5E277249F059</string> 673 | <key>version</key> 674 | <integer>3</integer> 675 | </dict> 676 | <dict> 677 | <key>config</key> 678 | <dict> 679 | <key>argument</key> 680 | <string></string> 681 | <key>passthroughargument</key> 682 | <false/> 683 | <key>variables</key> 684 | <dict> 685 | <key>title</key> 686 | <string>{query}</string> 687 | </dict> 688 | </dict> 689 | <key>type</key> 690 | <string>alfred.workflow.utility.argument</string> 691 | <key>uid</key> 692 | <string>5D0CA85B-D6F6-4677-9559-11AFA08F01BC</string> 693 | <key>version</key> 694 | <integer>1</integer> 695 | </dict> 696 | </array> 697 | <key>readme</key> 698 | <string># Alfred Noteplan v2 699 | 700 | Search, open, and create Noteplan notes with Alfred, and much more. 701 | 702 | --- 703 | 704 | ## Options when importing 705 | 706 | There's help under each field, but here are some additional notes / help 707 | 708 | ### Noteplan root (required) 709 | - Go to Noteplan > Preferences > Sync > Advanced > "Open local database folder", which opens the Finder 710 | - Ensure you have no item in this folder selected 711 | - Hit "Cmd"+"Option"+C 712 | - Paste this path as the Noteplan root 713 | 714 | ### Workflow triggers 715 | - **Main workflow** is used to invoke full text search (`n <query>`) and exact date parser (`n. <query>`) 716 | - **Create new note** invokes new note creation (`nn <title>`) 717 | 718 | ### New note template 719 | The all caps `TITLE` is replaced with the title you've chosen, helping Noteplan to name the file. If you've got more complicated template, keep this one simple, and upon creation of a new note use the Noteplan's templates and "Import a template" feature. 720 | 721 | ### Ignore files 722 | - this applies only to "Note" notes, not the calendar ones 723 | - each matcher should go to a separate line 724 | - files are matched from the beginning, so `archive` will match every note in a folder archive, while `archive/ignored` will match only those in subfolder of archive called ignored. 725 | - if you have two folders "archive/ignored" and "archived/ignored-not-really", "archive/ignored" will match both. Use "archive/ignored/" with a trailing slash to ensure only the files you want ignored are ignored. 726 | 727 | --- 728 | 729 | ## Usage 730 | - `n [Search phrase]` - Full text search. If there isn't any note available, "Create new note" command is the only result 731 | - `nh [Phrase]` - Search through all the hyperlinks you noted down - and open them immediately 732 | - `nc [Phrase]` - Search for all your titled code bits - and paste them to the frontmost app 733 | - `nd [date phrase]` - Very simple exact/relative date parser 734 | - `nn [Title of the note]` - Creates a new note, in the folder of your choice 735 | - `n !r` - Refresh note database 736 | - `n !rf` - Force refresh every note in the database 737 | - `n !!` - Show debug information 738 | 739 | The commands `n` and `nn` are configurable, the command `n. ` is the configured command `n` + `.` (selected because there's a macOS settings that translates double space to full stop and space, which (I think) `on` by default) 740 | 741 | All commands are configurable. To keep the workflow from being too complicated, if you don't wish to use a feature, just set the trigger to something complicated like `XYZ-extremely-unlikely-to-use` 742 | 743 | ### Hyperlinks 744 | 745 | Every hyperlink - `[The title and a description](https://example.com)` - is searchable, through the title and description and the link itself as well. **The default action for a hyperlink is to open it in a default browser**, to open the containing note, hit <kbd>CMD</kbd>+<kbd>↩</kbd>. 746 | 747 | ### Code bits 748 | 749 | Every block of code **with a title/description** is matched as a snippet. **Default action is "copy and paste in the frontmost app"**, to open the containing note, hit <kbd>CMD</kbd>+<kbd>↩</kbd>. 750 | 751 | #### Example code bit: 752 | 753 | ``` 754 | ```language (Title and a description in parentheses) 755 | This code bit will be matched as codebit by content, language and the title and description. 756 | ``` 757 | ``` 758 | 759 | ### Date parser 760 | - `t … today` - today's note 761 | - `y … yesterday` - yesterday's note 762 | - `tom … tomorrow` - tomorrow's note 763 | - `[20]?220401` - exact date in Ymd format, where the initial 20 is optional 764 | - `0401` - exact day, current year (month first) 765 | - `4/1` - exact day, current year (month first, leading zero optional) 766 | - `1.4` - exact day, current year (day first, leading zero optional) 767 | - `1 4` - exact day, current year (leading zero optional, d/m order configurable) 768 | - `[-+]? [number] [dw]` - relative date, number of days or weeks back and forward. spaces are optional 769 | - `[wmq]` - this week's (month's, quarter's) note 770 | - `[wmq] [number]` - weekly (monthly, quarterly) note of w/m/q X 771 | - `[wmq] -|+ [number]` - relative week's (month's, quarter's) note (spaces optional) 772 | - `yr|year` - this year's note 773 | - `yr|year [XY]` - note of the year 20XY 774 | - `yr|year -|+ [number]` - relative year (spaces optional) 775 | 776 | ## Installation 777 | 1. Configure the workflow 778 | - the most important and required part is the **Noteplan root folder** 779 | - get it through `Noteplan Options` > `Sync` > `'Advanced' for your active Sync option` > `Open local database` 780 | - this will open a Finder window 781 | - in this window, with **nothing selected**, press <kbd>Command</kbd>+<kbd>Option</kbd>+<kbd>C</kbd> to copy the pathname 782 | - paste that into the workflow import window 783 | 2. Trust the app. This step is necessary because [the app is not signed](#why-all-the-warnings). 784 | 1. Type `n ` in Alfred - macOS will warn you that this app is unsigned and you can move it to bin or cancel. 785 | 2. Open **System Settings** > **Privacy & Security**, scroll down, and click "Allow Anyway". (In macOS before 13/Ventura, _System Settings_ is called _System Preferences_.) 786 | 3. Type `n ` in Alfred again - macOS will warn you _again_ that this app was downloaded from the internet and might not be safe. 787 | 4. The dialog now has an **Open** option. Click **Open** to finalize the authorization. 788 | 3. Profit! 789 | 4. You can now do a search, date query or add a new n 790 | 791 | ## License 792 | 793 | Copyright (c) 2023 Adam Kiss, MIT License</string> 794 | <key>uidata</key> 795 | <dict> 796 | <key>053FDDB4-A265-4274-8F91-1BE7C16BC397</key> 797 | <dict> 798 | <key>colorindex</key> 799 | <integer>2</integer> 800 | <key>note</key> 801 | <string>SEARCH/CREATE</string> 802 | <key>xpos</key> 803 | <real>30</real> 804 | <key>ypos</key> 805 | <real>25</real> 806 | </dict> 807 | <key>0F615941-D8B5-4106-A152-607F8FB1F4CD</key> 808 | <dict> 809 | <key>colorindex</key> 810 | <integer>5</integer> 811 | <key>note</key> 812 | <string>CODE BITS</string> 813 | <key>xpos</key> 814 | <real>30</real> 815 | <key>ypos</key> 816 | <real>445</real> 817 | </dict> 818 | <key>32184673-6E45-4E1E-A9A3-5E277249F059</key> 819 | <dict> 820 | <key>colorindex</key> 821 | <integer>11</integer> 822 | <key>note</key> 823 | <string>GET FOLDERS</string> 824 | <key>xpos</key> 825 | <real>510</real> 826 | <key>ypos</key> 827 | <real>590</real> 828 | </dict> 829 | <key>583FB278-5756-4AC2-A2BB-EA55CED6B10F</key> 830 | <dict> 831 | <key>colorindex</key> 832 | <integer>11</integer> 833 | <key>note</key> 834 | <string>CREATE</string> 835 | <key>xpos</key> 836 | <real>30</real> 837 | <key>ypos</key> 838 | <real>590</real> 839 | </dict> 840 | <key>5D0CA85B-D6F6-4677-9559-11AFA08F01BC</key> 841 | <dict> 842 | <key>colorindex</key> 843 | <integer>11</integer> 844 | <key>note</key> 845 | <string>QUERY → TITLE</string> 846 | <key>xpos</key> 847 | <real>425</real> 848 | <key>ypos</key> 849 | <real>620</real> 850 | </dict> 851 | <key>68DA41FC-6D2C-4123-A82E-D20D0A3BBA66</key> 852 | <dict> 853 | <key>colorindex</key> 854 | <integer>9</integer> 855 | <key>note</key> 856 | <string>CLOSE</string> 857 | <key>xpos</key> 858 | <real>685</real> 859 | <key>ypos</key> 860 | <real>410</real> 861 | </dict> 862 | <key>748CC6DD-431D-47CA-B2A7-F54387FE69FC</key> 863 | <dict> 864 | <key>xpos</key> 865 | <real>240</real> 866 | <key>ypos</key> 867 | <real>185</real> 868 | </dict> 869 | <key>876A2F3F-9B6C-4253-92BA-D005783257A9</key> 870 | <dict> 871 | <key>colorindex</key> 872 | <integer>8</integer> 873 | <key>note</key> 874 | <string>WITH PASTE</string> 875 | <key>xpos</key> 876 | <real>685</real> 877 | <key>ypos</key> 878 | <real>150</real> 879 | </dict> 880 | <key>8CD51E99-89FA-439A-A640-C4174B1D5C01</key> 881 | <dict> 882 | <key>colorindex</key> 883 | <integer>7</integer> 884 | <key>note</key> 885 | <string>WITHOUT PASTING</string> 886 | <key>xpos</key> 887 | <real>685</real> 888 | <key>ypos</key> 889 | <real>20</real> 890 | </dict> 891 | <key>98B6F5C9-30A7-49D0-813C-ECF85C399CCA</key> 892 | <dict> 893 | <key>colorindex</key> 894 | <integer>2</integer> 895 | <key>note</key> 896 | <string>MATCH DATE</string> 897 | <key>xpos</key> 898 | <real>30</real> 899 | <key>ypos</key> 900 | <real>160</real> 901 | </dict> 902 | <key>E620799B-C916-42D7-87BE-B5AD280F147D</key> 903 | <dict> 904 | <key>colorindex</key> 905 | <integer>7</integer> 906 | <key>note</key> 907 | <string>HYPERLINKS</string> 908 | <key>xpos</key> 909 | <real>30</real> 910 | <key>ypos</key> 911 | <real>305</real> 912 | </dict> 913 | <key>E7234EA6-7AE9-4354-9CEC-95A19238A3FC</key> 914 | <dict> 915 | <key>colorindex</key> 916 | <integer>5</integer> 917 | <key>note</key> 918 | <string>BROWSE</string> 919 | <key>xpos</key> 920 | <real>685</real> 921 | <key>ypos</key> 922 | <real>280</real> 923 | </dict> 924 | </dict> 925 | <key>userconfigurationconfig</key> 926 | <array> 927 | <dict> 928 | <key>config</key> 929 | <dict> 930 | <key>default</key> 931 | <string>~/Library/Containers/co.noteplan.NotePlan-setapp/Data/Library/Application Support/co.noteplan.NotePlan-setapp</string> 932 | <key>filtermode</key> 933 | <integer>1</integer> 934 | <key>placeholder</key> 935 | <string></string> 936 | <key>required</key> 937 | <true/> 938 | </dict> 939 | <key>description</key> 940 | <string>This is where the folder of your Noteplan library, so this workflow can find the Cache database, and link to the matched notes for quicklookurl.</string> 941 | <key>label</key> 942 | <string>Noteplan Data Root</string> 943 | <key>type</key> 944 | <string>filepicker</string> 945 | <key>variable</key> 946 | <string>user_np_root</string> 947 | </dict> 948 | <dict> 949 | <key>config</key> 950 | <dict> 951 | <key>default</key> 952 | <string>n</string> 953 | <key>placeholder</key> 954 | <string></string> 955 | <key>required</key> 956 | <true/> 957 | <key>trim</key> 958 | <true/> 959 | </dict> 960 | <key>description</key> 961 | <string>Workflow trigger to start the search</string> 962 | <key>label</key> 963 | <string>Trigger: Main workflow</string> 964 | <key>type</key> 965 | <string>textfield</string> 966 | <key>variable</key> 967 | <string>workflow_trigger_open</string> 968 | </dict> 969 | <dict> 970 | <key>config</key> 971 | <dict> 972 | <key>default</key> 973 | <string>nn</string> 974 | <key>placeholder</key> 975 | <string></string> 976 | <key>required</key> 977 | <true/> 978 | <key>trim</key> 979 | <true/> 980 | </dict> 981 | <key>description</key> 982 | <string>Workflow trigger to start the create new note process</string> 983 | <key>label</key> 984 | <string>Trigger: Create new note</string> 985 | <key>type</key> 986 | <string>textfield</string> 987 | <key>variable</key> 988 | <string>workflow_trigger_new</string> 989 | </dict> 990 | <dict> 991 | <key>config</key> 992 | <dict> 993 | <key>default</key> 994 | <string>nh</string> 995 | <key>placeholder</key> 996 | <string></string> 997 | <key>required</key> 998 | <true/> 999 | <key>trim</key> 1000 | <true/> 1001 | </dict> 1002 | <key>description</key> 1003 | <string>Workflow trigger to start the hyperlink search</string> 1004 | <key>label</key> 1005 | <string>Trigger: Search hyperlinks</string> 1006 | <key>type</key> 1007 | <string>textfield</string> 1008 | <key>variable</key> 1009 | <string>workflow_trigger_hyperlinks</string> 1010 | </dict> 1011 | <dict> 1012 | <key>config</key> 1013 | <dict> 1014 | <key>default</key> 1015 | <string>nc</string> 1016 | <key>placeholder</key> 1017 | <string></string> 1018 | <key>required</key> 1019 | <true/> 1020 | <key>trim</key> 1021 | <true/> 1022 | </dict> 1023 | <key>description</key> 1024 | <string>Workflow trigger to start the code bit search</string> 1025 | <key>label</key> 1026 | <string>Trigger: Search code bits</string> 1027 | <key>type</key> 1028 | <string>textfield</string> 1029 | <key>variable</key> 1030 | <string>workflow_trigger_code_bits</string> 1031 | </dict> 1032 | <dict> 1033 | <key>config</key> 1034 | <dict> 1035 | <key>default</key> 1036 | <string>nd</string> 1037 | <key>placeholder</key> 1038 | <string></string> 1039 | <key>required</key> 1040 | <true/> 1041 | <key>trim</key> 1042 | <true/> 1043 | </dict> 1044 | <key>description</key> 1045 | <string>Workflow trigger to start the exact date matching</string> 1046 | <key>label</key> 1047 | <string>Trigger: Date matcher</string> 1048 | <key>type</key> 1049 | <string>textfield</string> 1050 | <key>variable</key> 1051 | <string>workflow_trigger_date</string> 1052 | </dict> 1053 | <dict> 1054 | <key>config</key> 1055 | <dict> 1056 | <key>default</key> 1057 | <string>en_GB</string> 1058 | <key>pairs</key> 1059 | <array> 1060 | <array> 1061 | <string>English (en_GB)</string> 1062 | <string>en_GB</string> 1063 | </array> 1064 | <array> 1065 | <string>English (en_US)</string> 1066 | <string>en_US</string> 1067 | </array> 1068 | <array> 1069 | <string>Deutsch</string> 1070 | <string>de_DE</string> 1071 | </array> 1072 | <array> 1073 | <string>Slovenčina</string> 1074 | <string>sk_SK</string> 1075 | </array> 1076 | </array> 1077 | </dict> 1078 | <key>description</key> 1079 | <string>What locale/language should the workflow using when preparing data?</string> 1080 | <key>label</key> 1081 | <string>Locale / Language</string> 1082 | <key>type</key> 1083 | <string>popupbutton</string> 1084 | <key>variable</key> 1085 | <string>user_locale</string> 1086 | </dict> 1087 | <dict> 1088 | <key>config</key> 1089 | <dict> 1090 | <key>default</key> 1091 | <string>1</string> 1092 | <key>pairs</key> 1093 | <array> 1094 | <array> 1095 | <string>Monday</string> 1096 | <string>1</string> 1097 | </array> 1098 | <array> 1099 | <string>Tuesday</string> 1100 | <string>2</string> 1101 | </array> 1102 | <array> 1103 | <string>Wednesday</string> 1104 | <string>3</string> 1105 | </array> 1106 | <array> 1107 | <string>Thursday</string> 1108 | <string>4</string> 1109 | </array> 1110 | <array> 1111 | <string>Friday</string> 1112 | <string>5</string> 1113 | </array> 1114 | <array> 1115 | <string>Saturday</string> 1116 | <string>6</string> 1117 | </array> 1118 | <array> 1119 | <string>Sunday</string> 1120 | <string>7</string> 1121 | </array> 1122 | </array> 1123 | </dict> 1124 | <key>description</key> 1125 | <string>When does your Noteplan week starts on?</string> 1126 | <key>label</key> 1127 | <string>Week starts on</string> 1128 | <key>type</key> 1129 | <string>popupbutton</string> 1130 | <key>variable</key> 1131 | <string>user_week_starts_on</string> 1132 | </dict> 1133 | <dict> 1134 | <key>config</key> 1135 | <dict> 1136 | <key>default</key> 1137 | <false/> 1138 | <key>required</key> 1139 | <false/> 1140 | <key>text</key> 1141 | <string>Day is first</string> 1142 | </dict> 1143 | <key>description</key> 1144 | <string>When searching for exact day with a space (`nd 1 4`), is the "1" a day or a month?</string> 1145 | <key>label</key> 1146 | <string>Exact date with space: days first</string> 1147 | <key>type</key> 1148 | <string>checkbox</string> 1149 | <key>variable</key> 1150 | <string>user_exact_day_first</string> 1151 | </dict> 1152 | <dict> 1153 | <key>config</key> 1154 | <dict> 1155 | <key>default</key> 1156 | <string>--- 1157 | title: TITLE 1158 | ---</string> 1159 | <key>required</key> 1160 | <false/> 1161 | <key>trim</key> 1162 | <false/> 1163 | <key>verticalsize</key> 1164 | <integer>6</integer> 1165 | </dict> 1166 | <key>description</key> 1167 | <string>The template used when you create a new note through workflow</string> 1168 | <key>label</key> 1169 | <string>New note template</string> 1170 | <key>type</key> 1171 | <string>textarea</string> 1172 | <key>variable</key> 1173 | <string>user_new_note_template</string> 1174 | </dict> 1175 | <dict> 1176 | <key>config</key> 1177 | <dict> 1178 | <key>default</key> 1179 | <string></string> 1180 | <key>required</key> 1181 | <false/> 1182 | <key>trim</key> 1183 | <true/> 1184 | <key>verticalsize</key> 1185 | <integer>3</integer> 1186 | </dict> 1187 | <key>description</key> 1188 | <string>Enter path fragments you'd like to ignore, one fragment per line. Each fragment is matched from beginning of the path, so if you'd like to ignore 'Things' inside the 'Writing', write the ignore line as 'writing/things'. Matching is not case sensitive</string> 1189 | <key>label</key> 1190 | <string>Ignore files matching</string> 1191 | <key>type</key> 1192 | <string>textarea</string> 1193 | <key>variable</key> 1194 | <string>user_ignore_files</string> 1195 | </dict> 1196 | </array> 1197 | <key>version</key> 1198 | <string>2.0.1-beta.1</string> 1199 | <key>webaddress</key> 1200 | <string>https://github.com/adamkiss/alfred-noteplan</string> 1201 | </dict> 1202 | </plist> 1203 | --------------------------------------------------------------------------------