{"action":"created","comment":{"url":"https://api.github.com/repos/bastibe/org-journal/pulls/comments/25557447","id":25557447,"diff_hunk":"@@ -381,6 +381,101 @@ If the date is not today, it won't be given a time.\"\n     (org-journal-mark-entries)\n     (calendar-exit)))\n \n+;;; Journal search facilities\n+;;\n+\n+(defun org-journal-search (str)\n+  \"Search for a string in the journal within a given interval.\n+See `org-read-date` for information on ways to specify dates.\"\n+  (interactive (list (read-string \"Enter a string to search for: \" nil 'org-journal-search-history)))\n+  (let ((org-read-date-prefer-future nil)\n+        (start (org-read-date nil t nil \"Enter a period start\"))\n+        (end (org-read-date nil t nil \"Enter a period end\")))\n+    (when (time-less-p end start)\n+      (error \"Period end cannot be before the start\"))\n+    (when (time-less-p (current-time) start)\n+      (error \"Period start cannot be in the future\"))\n+    (org-journal-search-by-string str start end)))\n+(defvar org-journal-search-history nil)\n+\n+(defun org-journal-search-by-string (str &optional period-start period-end)\n+  \"Search for a string within a given interval\"\n+  (let* ((files (org-journal-search-build-file-list period-start period-end))\n+         (results (org-journal-search-do-search str files)))\n+    (with-current-buffer-window\n+     \"*Org-journal search*\" nil nil\n+     (princ (concat \"Search results for \\\"\" str \"\\\": \\n\\n\"))\n+     (org-journal-search-print-results results))))\n+\n+(defun org-journal-search-build-file-list (&optional period-start period-end)\n+  \"Build a list of journal files within a given time interval\"\n+  (let ((files (directory-files org-journal-dir t\n+                                org-journal-file-pattern))\n+        result)\n+    (dolist (file files)\n+      (let ((filetime (org-journal-calendar-date->time\n+                       (org-journal-file-name->calendar-date\n+                        (file-name-base file)))))\n+        (cond ((not (and period-start period-end))\n+               (push file result))\n+\n+              ((and period-start period-end\n+                    (time-less-p period-start filetime)\n+                    (time-less-p filetime period-end))\n+               (push file result))\n+\n+              ((and period-start\n+                    (not period-end)\n+                    (time-less-p period-start filetime))\n+               (push file result))\n+\n+              ((and period-end\n+                    (not period-start)\n+                    (time-less-p filetime period-end))\n+               (push file result)))))\n+    result))\n+\n+(defun org-journal-search-do-search (str files)\n+  \"Search for a string within a list of files, return match pairs (PATH . LINENUM)\"\n+  (let (results)\n+    (dolist (fname files)\n+      (with-temp-buffer\n+        (insert-file-contents fname)\n+        (while (search-forward str nil t)\n+          (let* ((fullstr (buffer-substring-no-properties\n+                           (line-beginning-position)\n+                           (line-end-position)))\n+                 (res (list fname (line-number-at-pos) fullstr)))\n+            (push res results)))))\n+    results))\n+\n+(defun org-journal-search-print-results (results)\n+  \"Print search results using text buttons\"\n+  (dolist (res results)\n+    (let* ((fname (nth 0 res))\n+           (lnum (nth 1 res))\n+           (fullstr (nth 2 res))\n+           (time (org-journal-calendar-date->time\n+                  (org-journal-file-name->calendar-date\n+                   (file-name-base fname))))\n+           (label (format-time-string org-journal-date-format time)))\n+      (insert-text-button label\n+                          'action 'search-journal-follow-link-action","path":"org-journal.el","position":83,"original_position":83,"commit_id":"6012adc0dc536496edea78f1c51f906b17be9406","original_commit_id":"6012adc0dc536496edea78f1c51f906b17be9406","user":{"login":"vkazanov","id":47369,"avatar_url":"https://avatars.githubusercontent.com/u/47369?v=3","gravatar_id":"","url":"https://api.github.com/users/vkazanov","html_url":"https://github.com/vkazanov","followers_url":"https://api.github.com/users/vkazanov/followers","following_url":"https://api.github.com/users/vkazanov/following{/other_user}","gists_url":"https://api.github.com/users/vkazanov/gists{/gist_id}","starred_url":"https://api.github.com/users/vkazanov/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/vkazanov/subscriptions","organizations_url":"https://api.github.com/users/vkazanov/orgs","repos_url":"https://api.github.com/users/vkazanov/repos","events_url":"https://api.github.com/users/vkazanov/events{/privacy}","received_events_url":"https://api.github.com/users/vkazanov/received_events","type":"User","site_admin":false},"body":"Yes :-) Sorry for that, I guess I had the original prototype function in the global scope left.","created_at":"2015-02-28T13:28:56Z","updated_at":"2015-02-28T13:28:56Z","html_url":"https://github.com/bastibe/org-journal/pull/28#discussion_r25557447","pull_request_url":"https://api.github.com/repos/bastibe/org-journal/pulls/28","_links":{"self":{"href":"https://api.github.com/repos/bastibe/org-journal/pulls/comments/25557447"},"html":{"href":"https://github.com/bastibe/org-journal/pull/28#discussion_r25557447"},"pull_request":{"href":"https://api.github.com/repos/bastibe/org-journal/pulls/28"}}},"pull_request":{"url":"https://api.github.com/repos/bastibe/org-journal/pulls/28","id":30178729,"html_url":"https://github.com/bastibe/org-journal/pull/28","diff_url":"https://github.com/bastibe/org-journal/pull/28.diff","patch_url":"https://github.com/bastibe/org-journal/pull/28.patch","issue_url":"https://api.github.com/repos/bastibe/org-journal/issues/28","number":28,"state":"open","locked":false,"title":"#27 Basic journal search facility","user":{"login":"vkazanov","id":47369,"avatar_url":"https://avatars.githubusercontent.com/u/47369?v=3","gravatar_id":"","url":"https://api.github.com/users/vkazanov","html_url":"https://github.com/vkazanov","followers_url":"https://api.github.com/users/vkazanov/followers","following_url":"https://api.github.com/users/vkazanov/following{/other_user}","gists_url":"https://api.github.com/users/vkazanov/gists{/gist_id}","starred_url":"https://api.github.com/users/vkazanov/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/vkazanov/subscriptions","organizations_url":"https://api.github.com/users/vkazanov/orgs","repos_url":"https://api.github.com/users/vkazanov/repos","events_url":"https://api.github.com/users/vkazanov/events{/privacy}","received_events_url":"https://api.github.com/users/vkazanov/received_events","type":"User","site_admin":false},"body":"Here goes.\r\n\r\nThe main entry point is the `org-journal-search` function, which asks for a search string and two dates (start end). Dates are read using the `org-read-date` function, which allows a rather free-form date entry (like `-7d` or `-1m`) plus a calendar-based date selection.\r\n\r\nThe results are just a read-only buffer with clickable (mouse/keyboard) links. I am thinking about implementing a nicer mode for the result buffer, but for now this should do.\r\n\r\nI also played with a tag-based search, which collects tags from all the files and builds an index... Don't know if it's worth it.\r\n\r\nPlease, give it a try and let me know.","created_at":"2015-02-27T16:20:45Z","updated_at":"2015-02-28T13:28:57Z","closed_at":null,"merged_at":null,"merge_commit_sha":"b084d041a15b4cf1a93ae0dac5f190d5739bc2aa","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/bastibe/org-journal/pulls/28/commits","review_comments_url":"https://api.github.com/repos/bastibe/org-journal/pulls/28/comments","review_comment_url":"https://api.github.com/repos/bastibe/org-journal/pulls/comments{/number}","comments_url":"https://api.github.com/repos/bastibe/org-journal/issues/28/comments","statuses_url":"https://api.github.com/repos/bastibe/org-journal/statuses/6012adc0dc536496edea78f1c51f906b17be9406","head":{"label":"vkazanov:master","ref":"master","sha":"6012adc0dc536496edea78f1c51f906b17be9406","user":{"login":"vkazanov","id":47369,"avatar_url":"https://avatars.githubusercontent.com/u/47369?v=3","gravatar_id":"","url":"https://api.github.com/users/vkazanov","html_url":"https://github.com/vkazanov","followers_url":"https://api.github.com/users/vkazanov/followers","following_url":"https://api.github.com/users/vkazanov/following{/other_user}","gists_url":"https://api.github.com/users/vkazanov/gists{/gist_id}","starred_url":"https://api.github.com/users/vkazanov/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/vkazanov/subscriptions","organizations_url":"https://api.github.com/users/vkazanov/orgs","repos_url":"https://api.github.com/users/vkazanov/repos","events_url":"https://api.github.com/users/vkazanov/events{/privacy}","received_events_url":"https://api.github.com/users/vkazanov/received_events","type":"User","site_admin":false},"repo":{"id":27342848,"name":"org-journal","full_name":"vkazanov/org-journal","owner":{"login":"vkazanov","id":47369,"avatar_url":"https://avatars.githubusercontent.com/u/47369?v=3","gravatar_id":"","url":"https://api.github.com/users/vkazanov","html_url":"https://github.com/vkazanov","followers_url":"https://api.github.com/users/vkazanov/followers","following_url":"https://api.github.com/users/vkazanov/following{/other_user}","gists_url":"https://api.github.com/users/vkazanov/gists{/gist_id}","starred_url":"https://api.github.com/users/vkazanov/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/vkazanov/subscriptions","organizations_url":"https://api.github.com/users/vkazanov/orgs","repos_url":"https://api.github.com/users/vkazanov/repos","events_url":"https://api.github.com/users/vkazanov/events{/privacy}","received_events_url":"https://api.github.com/users/vkazanov/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/vkazanov/org-journal","description":"A simple org-mode based journaling mode","fork":true,"url":"https://api.github.com/repos/vkazanov/org-journal","forks_url":"https://api.github.com/repos/vkazanov/org-journal/forks","keys_url":"https://api.github.com/repos/vkazanov/org-journal/keys{/key_id}","collaborators_url":"https://api.github.com/repos/vkazanov/org-journal/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/vkazanov/org-journal/teams","hooks_url":"https://api.github.com/repos/vkazanov/org-journal/hooks","issue_events_url":"https://api.github.com/repos/vkazanov/org-journal/issues/events{/number}","events_url":"https://api.github.com/repos/vkazanov/org-journal/events","assignees_url":"https://api.github.com/repos/vkazanov/org-journal/assignees{/user}","branches_url":"https://api.github.com/repos/vkazanov/org-journal/branches{/branch}","tags_url":"https://api.github.com/repos/vkazanov/org-journal/tags","blobs_url":"https://api.github.com/repos/vkazanov/org-journal/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/vkazanov/org-journal/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/vkazanov/org-journal/git/refs{/sha}","trees_url":"https://api.github.com/repos/vkazanov/org-journal/git/trees{/sha}","statuses_url":"https://api.github.com/repos/vkazanov/org-journal/statuses/{sha}","languages_url":"https://api.github.com/repos/vkazanov/org-journal/languages","stargazers_url":"https://api.github.com/repos/vkazanov/org-journal/stargazers","contributors_url":"https://api.github.com/repos/vkazanov/org-journal/contributors","subscribers_url":"https://api.github.com/repos/vkazanov/org-journal/subscribers","subscription_url":"https://api.github.com/repos/vkazanov/org-journal/subscription","commits_url":"https://api.github.com/repos/vkazanov/org-journal/commits{/sha}","git_commits_url":"https://api.github.com/repos/vkazanov/org-journal/git/commits{/sha}","comments_url":"https://api.github.com/repos/vkazanov/org-journal/comments{/number}","issue_comment_url":"https://api.github.com/repos/vkazanov/org-journal/issues/comments{/number}","contents_url":"https://api.github.com/repos/vkazanov/org-journal/contents/{+path}","compare_url":"https://api.github.com/repos/vkazanov/org-journal/compare/{base}...{head}","merges_url":"https://api.github.com/repos/vkazanov/org-journal/merges","archive_url":"https://api.github.com/repos/vkazanov/org-journal/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/vkazanov/org-journal/downloads","issues_url":"https://api.github.com/repos/vkazanov/org-journal/issues{/number}","pulls_url":"https://api.github.com/repos/vkazanov/org-journal/pulls{/number}","milestones_url":"https://api.github.com/repos/vkazanov/org-journal/milestones{/number}","notifications_url":"https://api.github.com/repos/vkazanov/org-journal/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/vkazanov/org-journal/labels{/name}","releases_url":"https://api.github.com/repos/vkazanov/org-journal/releases{/id}","created_at":"2014-11-30T16:53:09Z","updated_at":"2015-02-27T16:15:05Z","pushed_at":"2015-02-27T16:15:05Z","git_url":"git://github.com/vkazanov/org-journal.git","ssh_url":"git@github.com:vkazanov/org-journal.git","clone_url":"https://github.com/vkazanov/org-journal.git","svn_url":"https://github.com/vkazanov/org-journal","homepage":null,"size":180,"stargazers_count":0,"watchers_count":0,"language":"Emacs Lisp","has_issues":false,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"bastibe:master","ref":"master","sha":"5ee55c69c0e0cbf0af4332e07eeba7b8204c050a","user":{"login":"bastibe","id":649181,"avatar_url":"https://avatars.githubusercontent.com/u/649181?v=3","gravatar_id":"","url":"https://api.github.com/users/bastibe","html_url":"https://github.com/bastibe","followers_url":"https://api.github.com/users/bastibe/followers","following_url":"https://api.github.com/users/bastibe/following{/other_user}","gists_url":"https://api.github.com/users/bastibe/gists{/gist_id}","starred_url":"https://api.github.com/users/bastibe/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/bastibe/subscriptions","organizations_url":"https://api.github.com/users/bastibe/orgs","repos_url":"https://api.github.com/users/bastibe/repos","events_url":"https://api.github.com/users/bastibe/events{/privacy}","received_events_url":"https://api.github.com/users/bastibe/received_events","type":"User","site_admin":false},"repo":{"id":10479904,"name":"org-journal","full_name":"bastibe/org-journal","owner":{"login":"bastibe","id":649181,"avatar_url":"https://avatars.githubusercontent.com/u/649181?v=3","gravatar_id":"","url":"https://api.github.com/users/bastibe","html_url":"https://github.com/bastibe","followers_url":"https://api.github.com/users/bastibe/followers","following_url":"https://api.github.com/users/bastibe/following{/other_user}","gists_url":"https://api.github.com/users/bastibe/gists{/gist_id}","starred_url":"https://api.github.com/users/bastibe/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/bastibe/subscriptions","organizations_url":"https://api.github.com/users/bastibe/orgs","repos_url":"https://api.github.com/users/bastibe/repos","events_url":"https://api.github.com/users/bastibe/events{/privacy}","received_events_url":"https://api.github.com/users/bastibe/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/bastibe/org-journal","description":"A simple org-mode based journaling mode","fork":false,"url":"https://api.github.com/repos/bastibe/org-journal","forks_url":"https://api.github.com/repos/bastibe/org-journal/forks","keys_url":"https://api.github.com/repos/bastibe/org-journal/keys{/key_id}","collaborators_url":"https://api.github.com/repos/bastibe/org-journal/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/bastibe/org-journal/teams","hooks_url":"https://api.github.com/repos/bastibe/org-journal/hooks","issue_events_url":"https://api.github.com/repos/bastibe/org-journal/issues/events{/number}","events_url":"https://api.github.com/repos/bastibe/org-journal/events","assignees_url":"https://api.github.com/repos/bastibe/org-journal/assignees{/user}","branches_url":"https://api.github.com/repos/bastibe/org-journal/branches{/branch}","tags_url":"https://api.github.com/repos/bastibe/org-journal/tags","blobs_url":"https://api.github.com/repos/bastibe/org-journal/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/bastibe/org-journal/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/bastibe/org-journal/git/refs{/sha}","trees_url":"https://api.github.com/repos/bastibe/org-journal/git/trees{/sha}","statuses_url":"https://api.github.com/repos/bastibe/org-journal/statuses/{sha}","languages_url":"https://api.github.com/repos/bastibe/org-journal/languages","stargazers_url":"https://api.github.com/repos/bastibe/org-journal/stargazers","contributors_url":"https://api.github.com/repos/bastibe/org-journal/contributors","subscribers_url":"https://api.github.com/repos/bastibe/org-journal/subscribers","subscription_url":"https://api.github.com/repos/bastibe/org-journal/subscription","commits_url":"https://api.github.com/repos/bastibe/org-journal/commits{/sha}","git_commits_url":"https://api.github.com/repos/bastibe/org-journal/git/commits{/sha}","comments_url":"https://api.github.com/repos/bastibe/org-journal/comments{/number}","issue_comment_url":"https://api.github.com/repos/bastibe/org-journal/issues/comments{/number}","contents_url":"https://api.github.com/repos/bastibe/org-journal/contents/{+path}","compare_url":"https://api.github.com/repos/bastibe/org-journal/compare/{base}...{head}","merges_url":"https://api.github.com/repos/bastibe/org-journal/merges","archive_url":"https://api.github.com/repos/bastibe/org-journal/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/bastibe/org-journal/downloads","issues_url":"https://api.github.com/repos/bastibe/org-journal/issues{/number}","pulls_url":"https://api.github.com/repos/bastibe/org-journal/pulls{/number}","milestones_url":"https://api.github.com/repos/bastibe/org-journal/milestones{/number}","notifications_url":"https://api.github.com/repos/bastibe/org-journal/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/bastibe/org-journal/labels{/name}","releases_url":"https://api.github.com/repos/bastibe/org-journal/releases{/id}","created_at":"2013-06-04T13:59:03Z","updated_at":"2015-01-26T19:54:26Z","pushed_at":"2014-12-20T08:21:32Z","git_url":"git://github.com/bastibe/org-journal.git","ssh_url":"git@github.com:bastibe/org-journal.git","clone_url":"https://github.com/bastibe/org-journal.git","svn_url":"https://github.com/bastibe/org-journal","homepage":null,"size":479,"stargazers_count":34,"watchers_count":34,"language":"Emacs Lisp","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":12,"mirror_url":null,"open_issues_count":4,"forks":12,"open_issues":4,"watchers":34,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/bastibe/org-journal/pulls/28"},"html":{"href":"https://github.com/bastibe/org-journal/pull/28"},"issue":{"href":"https://api.github.com/repos/bastibe/org-journal/issues/28"},"comments":{"href":"https://api.github.com/repos/bastibe/org-journal/issues/28/comments"},"review_comments":{"href":"https://api.github.com/repos/bastibe/org-journal/pulls/28/comments"},"review_comment":{"href":"https://api.github.com/repos/bastibe/org-journal/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/bastibe/org-journal/pulls/28/commits"},"statuses":{"href":"https://api.github.com/repos/bastibe/org-journal/statuses/6012adc0dc536496edea78f1c51f906b17be9406"}}}}