org-mouse.el 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970
  1. ;;; org-mouse.el --- Better mouse support for org-mode
  2. ;; Copyright (c) 2006 Piotr Zielinski
  3. ;;
  4. ;; Author: Piotr Zielinski <piotr dot zielinski at gmail dot com>
  5. ;; Version: 0.21
  6. ;; $Id: org-mouse.el 347 2006-11-12 23:57:50Z pz215 $
  7. ;;
  8. ;; The latest version of this file is available from
  9. ;;
  10. ;; http://www.cl.cam.ac.uk/~pz215/files/org-mouse.el
  11. ;;
  12. ;; This file is *NOT* part of GNU Emacs.
  13. ;; This file is distributed under the same terms as GNU Emacs.
  14. ;; This program is free software; you can redistribute it and/or
  15. ;; modify it under the terms of the GNU General Public License as
  16. ;; published by the Free Software Foundation; either version 2 of
  17. ;; the License, or (at your option) any later version.
  18. ;; This program is distributed in the hope that it will be
  19. ;; useful, but WITHOUT ANY WARRANTY; without even the implied
  20. ;; warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
  21. ;; PURPOSE. See the GNU General Public License for more details.
  22. ;; You should have received a copy of the GNU General Public
  23. ;; License along with this program; if not, write to the Free
  24. ;; Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
  25. ;; MA 02111-1307 USA
  26. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  27. ;;
  28. ;;; Commentary:
  29. ;;
  30. ;; Org-mouse provides better mouse support for org-mode. Org-mode is
  31. ;; a mode for keeping notes, maintaining ToDo lists, and doing project
  32. ;; planning with a fast and effective plain-text system. It is
  33. ;; available from
  34. ;;
  35. ;; http://staff.science.uva.nl/~dominik/Tools/org/
  36. ;;
  37. ;; Org-mouse implements the following features:
  38. ;; * following links with the left mouse button (in Emacs 22)
  39. ;; * subtree expansion/collapse (org-cycle) with the left mouse button
  40. ;; * several context menus on the right mouse button:
  41. ;; + general text
  42. ;; + headlines
  43. ;; + timestamps
  44. ;; + priorities
  45. ;; + links
  46. ;; + tags
  47. ;; * promoting/demoting/moving subtrees with mouse-3
  48. ;; + if the drag starts and ends in the same line then promote/demote
  49. ;; + otherwise move the subtree
  50. ;; * date/time extraction from selected text (requires a python script)
  51. ;; (eg. select text from your email and click "Add Appointment")
  52. ;;
  53. ;; The python script that automatically extracts date/time information
  54. ;; from a piece of English text is available from:
  55. ;;
  56. ;; http://www.cl.cam.ac.uk/~pz215/files/timeparser.py
  57. ;;
  58. ;; Use
  59. ;; ------------
  60. ;;
  61. ;; To use this package, put the following line in your .emacs:
  62. ;;
  63. ;; (require 'org-mouse)
  64. ;;
  65. ;; Tested with Emacs 22.0.50, org-mode 4.33
  66. ;; Fixme:
  67. ;; + deal with folding / unfolding issues
  68. ;; TODO (This list is only theoretical, if you'd like to have some
  69. ;; feature implemented or a bug fix please send me an email, even if
  70. ;; something similar appears in the list below. This will help me get
  71. ;; the priorities right.):
  72. ;;
  73. ;; + org-store-link, insert link
  74. ;; + org tables
  75. ;; + occur with the current word/tag (same menu item)
  76. ;; + ctrl-c ctrl-c, for example, renumber the current list
  77. ;; + internal links
  78. ;; Please email me with new feature suggestions / bugs
  79. ;; History:
  80. ;;
  81. ;; Version 0.21
  82. ;; + selected text activates its context menu
  83. ;; + shift-middleclick or right-drag inserts the text from the clipboard in the form of a link
  84. ;;
  85. ;; Version 0.20
  86. ;; + the new "TODO Status" submenu replaces the "Cycle TODO" menu item
  87. ;; + the TODO menu can now list occurrences of a specific TODO keyword
  88. ;; + #+STARTUP line is now recognized
  89. ;;
  90. ;; Version 0.19
  91. ;; + added support for dragging URLs to the org-buffer
  92. ;;
  93. ;; Version 0.18
  94. ;; + added support for agenda blocks
  95. ;;
  96. ;; Version 0.17
  97. ;; + toggle checkboxes with a single click
  98. ;;
  99. ;; Version 0.16
  100. ;; + added support for checkboxes
  101. ;;
  102. ;; Version 0.15
  103. ;; + org-mode now works with the Agenda buffer as well
  104. ;;
  105. ;; Version 0.14
  106. ;; + added a menu option that converts plain list items to outline items
  107. ;;
  108. ;; Version 0.13
  109. ;; + "Insert Heading" now inserts a sibling heading if the point is
  110. ;; on "***" and a child heading otherwise
  111. ;;
  112. ;; Version 0.12
  113. ;; + compatible with Emacs 21
  114. ;; + custom agenda commands added to the main menu
  115. ;; + moving trees should now work between windows in the same frame
  116. ;;
  117. ;; Version 0.11
  118. ;; + fixed org-mouse-at-link (thanks to Carsten)
  119. ;; + removed [follow-link] bindings
  120. ;;
  121. ;; Version 0.10
  122. ;; + added a menu option to remove highlights
  123. ;; + compatible with org-mode 4.21 now
  124. ;;
  125. ;; Version 0.08:
  126. ;; + trees can be moved/promoted/demoted by dragging with the right
  127. ;; mouse button (mouse-3)
  128. ;; + small changes in the above function
  129. ;;
  130. ;; Versions 0.01 -- 0.07: (I don't remember)
  131. (eval-when-compile (require 'cl))
  132. (defvar org-mouse-plain-list-regexp "\\([ \t]*\\)\\([-+*]\\|[0-9]+[.)]\\) ")
  133. (defvar org-mouse-direct t)
  134. (defgroup org-mouse nil
  135. "Org-mouse"
  136. :tag "Org Mouse."
  137. :group 'org)
  138. (defcustom org-mouse-punctuation ":"
  139. ""
  140. :group 'org-mouse
  141. :type 'string)
  142. (defun org-mouse-re-search-line (regexp)
  143. "Searches the current line for a given regular expression."
  144. (beginning-of-line)
  145. (re-search-forward regexp (point-at-eol) t))
  146. (defun org-mouse-end-headline ()
  147. "Go to the end of current headline (ignoring tags)."
  148. (interactive)
  149. (end-of-line)
  150. (skip-chars-backward "\t ")
  151. (when (looking-back ":[A-Za-z]+:")
  152. (skip-chars-backward ":A-Za-z")
  153. (skip-chars-backward "\t ")))
  154. (defun org-mouse-show-context-menu (event prefix)
  155. (interactive "@e \nP")
  156. (if (and (= (event-click-count event) 1)
  157. (or (not mark-active)
  158. (sit-for (/ double-click-time 1000.0))))
  159. (progn
  160. (select-window (posn-window (event-start event)))
  161. (when (not (org-mouse-mark-active))
  162. (goto-char (posn-point (event-start event)))
  163. (when (not (eolp)) (save-excursion (run-hooks 'post-command-hook)))
  164. (let ((redisplay-dont-pause t))
  165. (sit-for 0)))
  166. (if (functionp org-mouse-context-menu-function)
  167. (funcall org-mouse-context-menu-function event)
  168. (mouse-major-mode-menu event prefix))
  169. )
  170. (setq this-command 'mouse-save-then-kill)
  171. (mouse-save-then-kill event)))
  172. (defun org-mouse-line-position ()
  173. "Returns :beginning :middle :end"
  174. (cond
  175. ((eolp) :end)
  176. ((org-mouse-bolp) :begin)
  177. (t :middle)))
  178. (defun org-mouse-empty-line ()
  179. (save-excursion (beginning-of-line) (looking-at "[ \t]*$")))
  180. (defun org-mouse-next-heading ()
  181. "Goes to the next heading and if there is none, it ensures that the point is at the beginning of an empty line."
  182. (unless (outline-next-heading)
  183. (beginning-of-line)
  184. (unless (org-mouse-empty-line)
  185. (end-of-line)
  186. (newline))))
  187. (defun org-mouse-insert-heading ()
  188. (interactive)
  189. (case (org-mouse-line-position)
  190. (:begin (beginning-of-line)
  191. (org-insert-heading))
  192. (t (org-mouse-next-heading)
  193. (org-insert-heading))))
  194. (defun org-mouse-timestamp-today (&optional shift units)
  195. (interactive)
  196. (flet ((org-read-date (x &optional y) (current-time)))
  197. (org-time-stamp nil))
  198. (when shift
  199. (org-timestamp-change shift units)))
  200. (defun org-mouse-keyword-menu (keywords function &optional selected itemformat)
  201. (message "kmenu: %S" selected)
  202. (mapcar
  203. `(lambda (keyword)
  204. (vector (cond
  205. ((functionp ,itemformat) (funcall ,itemformat keyword))
  206. ((stringp ,itemformat) (format ,itemformat keyword))
  207. (t keyword))
  208. (list 'funcall ,function keyword)
  209. :style (cond
  210. ((null ,selected) t)
  211. ((functionp ,selected) 'toggle)
  212. (t 'radio))
  213. :selected (if (functionp ,selected)
  214. (and (funcall ,selected keyword) t)
  215. (equal ,selected keyword))))
  216. keywords))
  217. (defun org-mouse-remove-match-and-spaces ()
  218. (interactive)
  219. (replace-match "")
  220. (just-one-space))
  221. (defun org-mouse-replace-match-and-surround (newtext &optional fixedcase
  222. literal string subexp)
  223. "The same as replace-match, but surrounds the replacement with spaces."
  224. (apply 'replace-match rest)
  225. (save-excursion
  226. (goto-char (match-beginning (or subexp 0)))
  227. (just-one-space)
  228. (goto-char (match-end (or subexp 0)))
  229. (just-one-space)))
  230. (defun org-mouse-keyword-replace-menu (keywords &optional group itemformat)
  231. (setq group (or group 0))
  232. (let ((replace (org-mouse-match-closure
  233. 'org-mouse-replace-match-and-surround)))
  234. (append
  235. (org-mouse-keyword-menu
  236. keywords
  237. `(lambda (keyword) (funcall ,replace keyword t t nil ,group))
  238. (match-string group)
  239. itemformat)
  240. `(["None" org-mouse-remove-match-and-spaces
  241. :style radio
  242. :selected ,(not (member (match-string group) keywords))]))))
  243. (defvar org-mouse-context-menu-function nil)
  244. (make-variable-buffer-local 'org-mouse-context-menu-function)
  245. (defun org-mouse-show-headlines ()
  246. (interactive)
  247. (let ((this-command 'org-cycle)
  248. (last-command 'org-cycle)
  249. (org-cycle-global-status nil))
  250. (org-cycle '(4))
  251. (org-cycle '(4))))
  252. (defun org-mouse-show-overview ()
  253. (interactive)
  254. (let ((org-cycle-global-status nil))
  255. (org-cycle '(4))))
  256. (defun org-mouse-set-priority (priority)
  257. (flet ((read-char-exclusive () priority))
  258. (org-priority)))
  259. (defvar org-mouse-priority-regexp "\\[#\\([A-Z]\\)\\]"
  260. "Regular expression matching the priority indicator. Differs from `org-priority-regexp' in that it doesn't contain the leading '.*?'.")
  261. (defun org-mouse-get-priority (&optional default)
  262. (save-excursion
  263. (if (org-mouse-re-search-line org-mouse-priority-regexp)
  264. (match-string 1)
  265. (when default (char-to-string org-default-priority)))))
  266. (defun org-mouse-at-link ()
  267. (and (eq (get-text-property (point) 'face) 'org-link)
  268. (save-excursion
  269. (goto-char (previous-single-property-change (point) 'face))
  270. (or (looking-at org-bracket-link-regexp)
  271. (looking-at org-angle-link-re)
  272. (looking-at org-plain-link-re)))))
  273. (defun org-mouse-delete-timestamp ()
  274. "Deletes the current timestamp as well as the preceding
  275. SCHEDULED: or DEADLINE: or ANYTHINGLIKETHIS:"
  276. (when (or (org-at-date-range-p) (org-at-timestamp-p))
  277. (replace-match "") ; delete the timestamp
  278. (skip-chars-backward " :A-Z")
  279. (when (looking-at " *[A-Z][A-Z]+:")
  280. (replace-match ""))))
  281. (defun org-mouse-looking-at (regexp skipchars &optional movechars)
  282. (save-excursion
  283. (let ((point (point)))
  284. (if (looking-at regexp) t
  285. (skip-chars-backward skipchars)
  286. (forward-char (or movechars 0))
  287. (when (looking-at regexp)
  288. (> (match-end 0) point))))))
  289. (defun org-mouse-priority-list ()
  290. (let ((ret) (current org-lowest-priority))
  291. (while (>= current ?A)
  292. (push (char-to-string current) ret)
  293. (decf current))
  294. ret))
  295. (defun org-mouse-tag-menu () ;todo
  296. (append
  297. (let ((tags (org-split-string (org-get-tags) ":")))
  298. (org-mouse-keyword-menu
  299. (sort (mapcar 'car (org-get-buffer-tags)) 'string-lessp)
  300. `(lambda (tag)
  301. (org-mouse-set-tags
  302. (sort (if (member tag (quote ,tags))
  303. (delete tag (quote ,tags))
  304. (cons tag (quote ,tags)))
  305. 'string-lessp)))
  306. `(lambda (tag) (member tag (quote ,tags)))
  307. ))
  308. '("--"
  309. ["Align Tags Here" (org-set-tags nil t) t]
  310. ["Align Tags in Buffer" (org-set-tags t t) t]
  311. ["Set Tags ..." (org-set-tags) t])))
  312. (defun org-mouse-set-tags (tags)
  313. (save-excursion
  314. ;; remove existing tags first
  315. (beginning-of-line)
  316. (when (org-mouse-re-search-line ":\\(\\([A-Za-z_]+:\\)+\\)")
  317. (replace-match ""))
  318. ;; set new tags if any
  319. (when tags
  320. (end-of-line)
  321. (insert " :" (mapconcat 'identity tags ":") ":")
  322. (org-set-tags nil t))))
  323. (defun org-mouse-insert-checkbox ()
  324. (interactive)
  325. (and (org-at-item-p)
  326. (goto-char (match-end 0))
  327. (unless (org-at-item-checkbox-p)
  328. (delete-horizontal-space)
  329. (insert " [ ] "))))
  330. (defun org-mouse-agenda-type (type)
  331. (case type
  332. ('tags "Tags: ")
  333. ('todo "TODO: ")
  334. ('tags-tree "Tags tree: ")
  335. ('todo-tree "TODO tree: ")
  336. ('occur-tree "Occur tree: ")
  337. (t "Agenda command ???")))
  338. (defun org-mouse-list-options-menu (alloptions &optional function)
  339. (let ((options (save-match-data
  340. (split-string (match-string-no-properties 1)))))
  341. (print options)
  342. (loop for name in alloptions
  343. collect
  344. (vector name
  345. `(progn
  346. (replace-match
  347. (mapconcat 'identity
  348. (sort (if (member ',name ',options)
  349. (delete ',name ',options)
  350. (cons ',name ',options))
  351. 'string-lessp)
  352. " ")
  353. nil nil nil 1)
  354. (when (functionp ',function) (funcall ',function)))
  355. :style 'toggle
  356. :selected (and (member name options) t)))))
  357. (defun org-mouse-clip-text (text maxlength)
  358. (if (> (length text) maxlength)
  359. (concat (substring text 0 (- maxlength 3)) "...")
  360. text))
  361. (defun org-mouse-popup-global-menu ()
  362. (popup-menu
  363. `("Main Menu"
  364. ["Show Overview" org-mouse-show-overview t]
  365. ["Show Headlines" org-mouse-show-headlines t]
  366. ["Show All" show-all t]
  367. ["Remove Highlights" org-remove-occur-highlights
  368. :visible org-occur-highlights]
  369. "--"
  370. ["Check Deadlines"
  371. (if (functionp 'org-check-deadlines-and-todos)
  372. (org-check-deadlines-and-todos org-deadline-warning-days)
  373. (org-check-deadlines org-deadline-warning-days)) t]
  374. ["Check TODOs" org-show-todo-tree t]
  375. ("Check Tags"
  376. ,@(org-mouse-keyword-menu
  377. (sort (mapcar 'car (org-get-buffer-tags)) 'string-lessp)
  378. '(lambda (tag) (org-tags-sparse-tree nil tag)))
  379. "--"
  380. ["Custom Tag ..." org-tags-sparse-tree t])
  381. ["Check Phrase ..." org-occur]
  382. "--"
  383. ["Display Agenda" org-agenda-list t]
  384. ["Display Timeline" org-timeline t]
  385. ["Display TODO List" org-todo-list t]
  386. ("Display Tags"
  387. ,@(org-mouse-keyword-menu
  388. (sort (mapcar 'car (org-get-buffer-tags)) 'string-lessp)
  389. '(lambda (tag) (org-tags-view nil tag)))
  390. "--"
  391. ["Custom Tag ..." org-tags-view t])
  392. ["Display Calendar" org-goto-calendar t]
  393. "--"
  394. ,@(org-mouse-keyword-menu
  395. (mapcar 'car org-agenda-custom-commands)
  396. '(lambda (key)
  397. (eval `(flet ((read-char-exclusive () (string-to-char ,key)))
  398. (org-agenda nil))))
  399. nil
  400. '(lambda (key)
  401. (let ((entry (assoc key org-agenda-custom-commands)))
  402. (org-mouse-clip-text
  403. (cond
  404. ((stringp (nth 1 entry)) (nth 1 entry))
  405. ((stringp (nth 2 entry))
  406. (concat (org-mouse-agenda-type (nth 1 entry))
  407. (nth 2 entry)))
  408. (t "Agenda Command '%s'"))
  409. 30))))
  410. ;; )
  411. "--"
  412. ["Delete Blank Lines" delete-blank-lines
  413. :visible (org-mouse-empty-line)]
  414. ["Insert Checkbox" org-mouse-insert-checkbox
  415. :visible (and (org-at-item-p) (not (org-at-item-checkbox-p)))]
  416. ["Insert Checkboxes"
  417. (org-mouse-for-each-item 'org-mouse-insert-checkbox)
  418. :visible (and (org-at-item-p) (not (org-at-item-checkbox-p)))]
  419. ["Plain List to Outline" org-mouse-transform-to-outline
  420. :visible (org-at-item-p)])))
  421. ; ["Jump" org-goto])))
  422. (defun org-mouse-get-context (contextlist context)
  423. (let ((contextdata (find-if (lambda (x) (eq (car x) context)) contextlist)))
  424. (when contextdata
  425. (save-excursion
  426. (goto-char (nth 1 contextdata))
  427. ; (looking-at regexp)))))
  428. (re-search-forward ".*" (nth 2 contextdata))))))
  429. (defun org-mouse-for-each-item (function)
  430. (save-excursion
  431. (ignore-errors
  432. (while t (org-previous-item)))
  433. (ignore-errors
  434. (while t
  435. (funcall function)
  436. (org-next-item)))))
  437. (defun org-mouse-bolp ()
  438. "Returns true if there only spaces, tabs, and '*', between the beginning of line and the point"
  439. (save-excursion
  440. (skip-chars-backward " \t*") (bolp)))
  441. (defun org-mouse-insert-item (text)
  442. (case (org-mouse-line-position)
  443. (:begin ; insert before
  444. (beginning-of-line)
  445. (looking-at "[ \t]*")
  446. (open-line 1)
  447. (indent-to (- (match-end 0) (match-beginning 0)))
  448. (insert "+ "))
  449. (:middle ; insert after
  450. (end-of-line)
  451. (newline t)
  452. (indent-relative)
  453. (insert "+ "))
  454. (:end ; insert text here
  455. (skip-chars-backward " \t")
  456. (kill-region (point) (point-at-eol))
  457. (unless (looking-back org-mouse-punctuation)
  458. (insert (concat org-mouse-punctuation " ")))))
  459. (insert text)
  460. (beginning-of-line))
  461. (defadvice dnd-insert-text (around org-mouse-dnd-insert-text activate)
  462. (if (eq major-mode 'org-mode)
  463. (org-mouse-insert-item text)
  464. ad-do-it))
  465. (defadvice dnd-open-file (around org-mouse-dnd-open-file activate)
  466. (if (eq major-mode 'org-mode)
  467. (org-mouse-insert-item uri)
  468. ad-do-it))
  469. (defun org-mouse-match-closure (function)
  470. (let ((match (match-data t)))
  471. `(lambda (&rest rest)
  472. (save-match-data
  473. (set-match-data ',match)
  474. (apply ',function rest)))))
  475. (defun org-mouse-match-todo-keyword ()
  476. (save-excursion
  477. (org-back-to-heading)
  478. (if (looking-at outline-regexp) (goto-char (match-end 0)))
  479. (or (looking-at (concat " +" org-todo-regexp " *"))
  480. (looking-at " \\( *\\)"))))
  481. (defun org-mouse-yank-link (click)
  482. (interactive "e")
  483. ;; Give temporary modes such as isearch a chance to turn off.
  484. (run-hooks 'mouse-leave-buffer-hook)
  485. (mouse-set-point click)
  486. (setq mouse-selection-click-count 0)
  487. (delete-horizontal-space)
  488. (insert-for-yank (concat " [[" (current-kill 0) "]] ")))
  489. (defun org-mouse-context-menu (&optional event)
  490. (let ((stamp-prefixes (list org-deadline-string org-scheduled-string))
  491. (contextlist (org-context)))
  492. (flet ((get-context (context) (org-mouse-get-context contextlist context)))
  493. (cond
  494. ((org-mouse-mark-active)
  495. (let ((region-string (buffer-substring (region-beginning) (region-end))))
  496. (popup-menu
  497. `(nil
  498. ["Sparse Tree" (org-occur ',region-string)]
  499. ["Find in Buffer" (occur ',region-string)]
  500. ["Grep in Current Dir"
  501. (grep (format "grep -rnH -e '%s' *" ',region-string))]
  502. ["Grep in Parent Dir"
  503. (grep (format "grep -rnH -e '%s' ../*" ',region-string))]
  504. "--"
  505. ["Convert to Link"
  506. (progn (save-excursion (goto-char (region-beginning)) (insert "[["))
  507. (save-excursion (goto-char (region-end)) (insert "]]")))]
  508. ["Insert Link Here" (org-mouse-yank-link ',event)]))))
  509. ((save-excursion (beginning-of-line) (looking-at "#\\+STARTUP: \\(.*\\)"))
  510. (popup-menu
  511. `(nil
  512. ,@(org-mouse-list-options-menu (mapcar 'car org-startup-options)
  513. 'org-mode-restart))))
  514. ((or (eolp)
  515. (and (looking-at " \\|\t") (looking-back " \\|\t")))
  516. (org-mouse-popup-global-menu))
  517. ((get-context :checkbox)
  518. (popup-menu
  519. '(nil
  520. ["Toggle" org-toggle-checkbox t]
  521. ["Remove" org-mouse-remove-match-and-spaces t]
  522. ""
  523. ["All Clear" (org-mouse-for-each-item
  524. (lambda ()
  525. (when (save-excursion (org-at-item-checkbox-p))
  526. (replace-match "[ ]"))))]
  527. ["All Set" (org-mouse-for-each-item
  528. (lambda ()
  529. (when (save-excursion (org-at-item-checkbox-p))
  530. (replace-match "[X]"))))]
  531. ["All Toggle" (org-mouse-for-each-item 'org-toggle-checkbox) t]
  532. ["All Remove" (org-mouse-for-each-item
  533. (lambda ()
  534. (when (save-excursion (org-at-item-checkbox-p))
  535. (org-mouse-remove-match-and-spaces))))]
  536. )))
  537. ((and (org-mouse-looking-at "\\b\\w+" "a-zA-Z0-9_")
  538. (member (match-string 0) org-todo-keywords))
  539. (popup-menu
  540. `(nil
  541. ,@(org-mouse-keyword-replace-menu org-todo-keywords)
  542. "--"
  543. ["Check TODOs" org-show-todo-tree t]
  544. ["List all TODO keywords" org-todo-list t]
  545. [,(format "List only %s" (match-string 0))
  546. (org-todo-list (match-string 0)) t]
  547. )))
  548. ((and (org-mouse-looking-at "\\b[A-Z]+:" "A-Z")
  549. (member (match-string 0) stamp-prefixes))
  550. (popup-menu
  551. `(nil
  552. ,@(org-mouse-keyword-replace-menu stamp-prefixes)
  553. "--"
  554. ["Check Deadlines" org-check-deadlines t]
  555. )))
  556. ((org-mouse-looking-at org-mouse-priority-regexp "[]A-Z#") ; priority
  557. (popup-menu `(nil ,@(org-mouse-keyword-replace-menu
  558. (org-mouse-priority-list) 1 "Priority %s"))))
  559. ((org-mouse-at-link)
  560. (popup-menu
  561. '(nil
  562. ["Open" org-open-at-point t]
  563. ["Open in Emacs" (org-open-at-point t) t]
  564. "--"
  565. ["Copy link" (kill-new (match-string 0))]
  566. ["Cut link"
  567. (progn
  568. (kill-region (match-beginning 0) (match-end 0))
  569. (just-one-space))]
  570. ; ["Paste file link" ((insert "file:") (yank))]
  571. )))
  572. ((org-mouse-looking-at ":\\([A-Za-z0-9_]+\\):" "A-Za-z0-9_" -1) ;tags
  573. (popup-menu
  574. `(nil
  575. [,(format "Display '%s'" (match-string 1))
  576. (org-tags-view nil ,(match-string 1))]
  577. [,(format "Sparse Tree '%s'" (match-string 1))
  578. (org-tags-sparse-tree nil ,(match-string 1))]
  579. "--"
  580. ,@(org-mouse-tag-menu))))
  581. ((org-at-timestamp-p)
  582. (popup-menu
  583. '(nil
  584. ["Show Day" org-open-at-point t]
  585. ["Change Timestamp" org-time-stamp t]
  586. ["Delete Timestamp" (org-mouse-delete-timestamp) t]
  587. ["Compute Time Range" org-evaluate-time-range (org-at-date-range-p)]
  588. "--"
  589. ["Set for Today" org-mouse-timestamp-today]
  590. ["Set for Tomorrow" (org-mouse-timestamp-today 1 'day)]
  591. ["Set in 1 Week" (org-mouse-timestamp-today 7 'day)]
  592. ["Set in 2 Weeks" (org-mouse-timestamp-today 14 'day)]
  593. ["Set in a Month" (org-mouse-timestamp-today 1 'month)]
  594. "--"
  595. ["+ 1 Day" (org-timestamp-change 1 'day)]
  596. ["+ 1 Week" (org-timestamp-change 7 'day)]
  597. ["+ 1 Month" (org-timestamp-change 1 'month)]
  598. "--"
  599. ["- 1 Day" (org-timestamp-change -1 'day)]
  600. ["- 1 Week" (org-timestamp-change -7 'day)]
  601. ["- 1 Month" (org-timestamp-change -1 'month)])))
  602. ((and (assq :headline contextlist) (not (eolp)))
  603. (let ((priority (org-mouse-get-priority t)))
  604. (popup-menu
  605. `("Headline Menu"
  606. ("Tags and Priorities"
  607. ,@(org-mouse-keyword-menu
  608. (org-mouse-priority-list)
  609. '(lambda (keyword)
  610. (org-mouse-set-priority (string-to-char keyword)))
  611. priority "Priority %s")
  612. "--"
  613. ,@(org-mouse-tag-menu))
  614. ("TODO Status"
  615. ,@(progn (org-mouse-match-todo-keyword)
  616. (org-mouse-keyword-replace-menu org-todo-keywords 1)))
  617. ["Show Tags"
  618. (with-current-buffer org-mouse-main-buffer (org-agenda-show-tags))
  619. :visible (not org-mouse-direct)]
  620. ["Show Priority"
  621. (with-current-buffer org-mouse-main-buffer (org-agenda-show-priority))
  622. :visible (not org-mouse-direct)]
  623. ,@(if org-mouse-direct '("--") nil)
  624. ["New Heading" org-mouse-insert-heading :visible org-mouse-direct]
  625. ["Set Deadline"
  626. (progn (org-mouse-end-headline) (insert " ") (org-deadline))
  627. :active (not (save-excursion
  628. (org-mouse-re-search-line org-deadline-regexp)))]
  629. ["Schedule Task"
  630. (progn (org-mouse-end-headline) (insert " ") (org-schedule))
  631. :active (not (save-excursion
  632. (org-mouse-re-search-line org-scheduled-regexp)))]
  633. ["Insert Timestamp"
  634. (progn (org-mouse-end-headline) (insert " ") (org-time-stamp nil)) t]
  635. ; ["Timestamp (inactive)" org-time-stamp-inactive t]
  636. "--"
  637. ["Archive Subtree" org-archive-subtree]
  638. ["Cut Subtree" org-cut-special]
  639. ["Copy Subtree" org-copy-special]
  640. ["Paste Subtree" org-paste-special :visible org-mouse-direct]
  641. "--"
  642. ["Move Trees" org-mouse-move-tree :active nil]
  643. ))))
  644. (t
  645. (org-mouse-popup-global-menu))))))
  646. ;; (defun org-mouse-at-regexp (regexp)
  647. ;; (save-excursion
  648. ;; (let ((point (point))
  649. ;; (bol (progn (beginning-of-line) (point)))
  650. ;; (eol (progn (end-of-line) (point))))
  651. ;; (goto-char point)
  652. ;; (re-search-backward regexp bol 1)
  653. ;; (and (not (eolp))
  654. ;; (progn (forward-char)
  655. ;; (re-search-forward regexp eol t))
  656. ;; (<= (match-beginning 0) point)))))
  657. (defun org-mouse-mark-active ()
  658. (and mark-active transient-mark-mode))
  659. (defun org-mouse-in-region-p (pos)
  660. (and (org-mouse-mark-active)
  661. (>= pos (region-beginning))
  662. (< pos (region-end))))
  663. (defun org-mouse-down-mouse (event)
  664. (interactive "e")
  665. (setq this-command last-command)
  666. (unless (and (= 1 (event-click-count event))
  667. (org-mouse-in-region-p (posn-point (event-start event))))
  668. (mouse-drag-region event)))
  669. (add-hook 'org-mode-hook
  670. '(lambda ()
  671. (setq org-mouse-context-menu-function 'org-mouse-context-menu)
  672. ; (define-key org-mouse-map [follow-link] 'mouse-face)
  673. (define-key org-mouse-map (if (featurep 'xemacs) [button3] [mouse-3]) nil)
  674. (define-key org-mode-map [mouse-3] 'org-mouse-show-context-menu)
  675. (define-key org-mode-map [down-mouse-1] 'org-mouse-down-mouse)
  676. (define-key org-mouse-map [C-drag-mouse-1] 'org-mouse-move-tree)
  677. (define-key org-mouse-map [C-down-mouse-1] 'org-mouse-move-tree-start)
  678. (define-key org-mode-map [S-mouse-2] 'org-mouse-yank-link)
  679. (define-key org-mode-map [drag-mouse-3] 'org-mouse-yank-link)
  680. (define-key org-mouse-map [drag-mouse-3] 'org-mouse-move-tree)
  681. (define-key org-mouse-map [down-mouse-3] 'org-mouse-move-tree-start)
  682. (font-lock-add-keywords nil
  683. `((,outline-regexp
  684. 0 `(face org-link mouse-face highlight keymap ,org-mouse-map)
  685. 'prepend)
  686. ("^[ \t]*\\([-+*]\\|[0-9]+[.)]\\) +"
  687. (1 `(face org-link keymap ,org-mouse-map mouse-face highlight) 'prepend))
  688. ("^[ \t]*\\([-+*]\\|[0-9]+[.)]\\) +\\(\\[[ X]\\]\\)"
  689. (2 `(face bold keymap ,org-mouse-map mouse-face highlight) t)))
  690. t)
  691. (defadvice org-open-at-point (around org-mouse-open-at-point activate)
  692. (let ((context (org-context)))
  693. (cond
  694. ((assq :headline-stars context) (org-cycle))
  695. ((assq :checkbox context) (org-toggle-checkbox))
  696. ((assq :item-bullet context)
  697. (let ((org-cycle-include-plain-lists t)) (org-cycle)))
  698. (t ad-do-it))))))
  699. (defun org-mouse-move-tree-start (event)
  700. (interactive "e")
  701. (message "Same line: promote/demote, (***):move before, (text): make a child"))
  702. (defun org-mouse-make-marker (position)
  703. (with-current-buffer (window-buffer (posn-window position))
  704. (copy-marker (posn-point position))))
  705. (defun org-mouse-move-tree (event)
  706. ;; todo: handle movements between different buffers
  707. (interactive "e")
  708. (save-excursion
  709. (let* ((start (org-mouse-make-marker (event-start event)))
  710. (end (org-mouse-make-marker (event-end event)))
  711. (sbuf (marker-buffer start))
  712. (ebuf (marker-buffer end)))
  713. (when (and sbuf ebuf)
  714. (set-buffer sbuf)
  715. (goto-char start)
  716. (org-back-to-heading)
  717. (if (and (eq sbuf ebuf)
  718. (equal
  719. (point)
  720. (save-excursion (goto-char end) (org-back-to-heading) (point))))
  721. ;; if the same line then promote/demote
  722. (if (>= end start) (org-demote-subtree) (org-promote-subtree))
  723. ;; if different lines then move
  724. (org-cut-subtree)
  725. (set-buffer ebuf)
  726. (goto-char end)
  727. (org-back-to-heading)
  728. (when (and (eq sbuf ebuf)
  729. (equal
  730. (point)
  731. (save-excursion (goto-char start)
  732. (org-back-to-heading) (point))))
  733. (outline-end-of-subtree)
  734. (end-of-line)
  735. (if (eobp) (newline) (forward-char)))
  736. (when (looking-at outline-regexp)
  737. (let ((level (- (match-end 0) (match-beginning 0))))
  738. (when (> end (match-end 0))
  739. (outline-end-of-subtree)
  740. (end-of-line)
  741. (if (eobp) (newline) (forward-char))
  742. (setq level (1+ level)))
  743. (org-paste-subtree level)
  744. (save-excursion
  745. (outline-end-of-subtree)
  746. (when (bolp) (delete-char -1))))))))))
  747. (defun org-mouse-transform-to-outline ()
  748. (interactive)
  749. (org-back-to-heading)
  750. (let ((minlevel 1000)
  751. (replace-text (concat (match-string 0) "* ")))
  752. (beginning-of-line 2)
  753. (save-excursion
  754. (while (not (or (eobp) (looking-at outline-regexp)))
  755. (when (looking-at org-mouse-plain-list-regexp)
  756. (setq minlevel (min minlevel (- (match-end 1) (match-beginning 1)))))
  757. (forward-line)))
  758. (while (not (or (eobp) (looking-at outline-regexp)))
  759. (when (and (looking-at org-mouse-plain-list-regexp)
  760. (eq minlevel (- (match-end 1) (match-beginning 1))))
  761. (replace-match replace-text))
  762. (forward-line))))
  763. (defun org-mouse-do-remotely (command)
  764. ; (org-agenda-check-no-diary)
  765. (when (get-text-property (point) 'org-marker)
  766. (let* ((anticol (- (point-at-eol) (point)))
  767. (marker (get-text-property (point) 'org-marker))
  768. (buffer (marker-buffer marker))
  769. (pos (marker-position marker))
  770. (hdmarker (get-text-property (point) 'org-hd-marker))
  771. (buffer-read-only nil)
  772. (newhead "--- removed ---")
  773. (org-mouse-direct nil)
  774. (org-mouse-main-buffer (current-buffer)))
  775. (when (eq (with-current-buffer buffer major-mode) 'org-mode)
  776. (let ((endmarker (save-excursion
  777. (set-buffer buffer)
  778. (outline-end-of-subtree)
  779. (forward-char 1)
  780. (copy-marker (point)))))
  781. (with-current-buffer buffer
  782. (widen)
  783. (goto-char pos)
  784. (org-show-hidden-entry)
  785. (save-excursion
  786. (and (outline-next-heading)
  787. (org-flag-heading nil))) ; show the next heading
  788. (org-back-to-heading)
  789. (setq marker (copy-marker (point)))
  790. (goto-char (max (point-at-bol) (- (point-at-eol) anticol)))
  791. (funcall command)
  792. (unless (eq (marker-position marker) (marker-position endmarker))
  793. (setq newhead (org-get-heading))))
  794. (beginning-of-line 1)
  795. (save-excursion
  796. (org-agenda-change-all-lines newhead hdmarker 'fixface)))
  797. t))))
  798. (defun org-mouse-agenda-context-menu (&optional event)
  799. (or (org-mouse-do-remotely 'org-mouse-context-menu)
  800. (popup-menu
  801. '("Agenda"
  802. ("Agenda Files")
  803. "--"
  804. ["Rebuild Buffer" org-agenda-redo t]
  805. ["New Diary Entry"
  806. org-agenda-diary-entry (org-agenda-check-type nil 'agenda 'timeline) t]
  807. "--"
  808. ["Goto Today" org-agenda-goto-today
  809. (org-agenda-check-type nil 'agenda 'timeline) t]
  810. ["Display Calendar" org-agenda-goto-calendar
  811. (org-agenda-check-type nil 'agenda 'timeline) t]
  812. ("Calendar Commands"
  813. ["Phases of the Moon" org-agenda-phases-of-moon
  814. (org-agenda-check-type nil 'agenda 'timeline)]
  815. ["Sunrise/Sunset" org-agenda-sunrise-sunset
  816. (org-agenda-check-type nil 'agenda 'timeline)]
  817. ["Holidays" org-agenda-holidays
  818. (org-agenda-check-type nil 'agenda 'timeline)]
  819. ["Convert" org-agenda-convert-date
  820. (org-agenda-check-type nil 'agenda 'timeline)]
  821. "--"
  822. ["Create iCalendar file" org-export-icalendar-combine-agenda-files t])
  823. "--"
  824. ["Day View" org-agenda-day-view
  825. :active (org-agenda-check-type nil 'agenda)
  826. :style radio :selected (equal org-agenda-ndays 1)]
  827. ["Week View" org-agenda-week-view
  828. :active (org-agenda-check-type nil 'agenda)
  829. :style radio :selected (equal org-agenda-ndays 7)]
  830. "--"
  831. ["Show Logbook entries" org-agenda-log-mode
  832. :style toggle :selected org-agenda-show-log
  833. :active (org-agenda-check-type nil 'agenda 'timeline)]
  834. ["Include Diary" org-agenda-toggle-diary
  835. :style toggle :selected org-agenda-include-diary
  836. :active (org-agenda-check-type nil 'agenda)]
  837. ["Use Time Grid" org-agenda-toggle-time-grid
  838. :style toggle :selected org-agenda-use-time-grid
  839. :active (org-agenda-check-type nil 'agenda)]
  840. ["Follow Mode" org-agenda-follow-mode
  841. :style toggle :selected org-agenda-follow-mode]
  842. "--"
  843. ["Quit" org-agenda-quit t]
  844. ["Exit and Release Buffers" org-agenda-exit t]
  845. ))))
  846. (defun org-mouse-get-gesture (event)
  847. (let ((startxy (posn-x-y (event-start event)))
  848. (endxy (posn-x-y (event-end event))))
  849. (if (< (car startxy) (car endxy)) :right :left)))
  850. ; (setq org-agenda-mode-hook nil)
  851. (add-hook 'org-agenda-mode-hook
  852. '(lambda ()
  853. (setq org-mouse-context-menu-function 'org-mouse-agenda-context-menu)
  854. (define-key org-agenda-keymap
  855. (if (featurep 'xemacs) [button3] [mouse-3])
  856. 'org-mouse-show-context-menu)
  857. (define-key org-agenda-keymap [down-mouse-3] 'org-mouse-move-tree-start)
  858. (define-key org-agenda-keymap [C-mouse-4] 'org-agenda-earlier)
  859. (define-key org-agenda-keymap [C-mouse-5] 'org-agenda-later)
  860. (define-key org-agenda-keymap [drag-mouse-3]
  861. '(lambda (event) (interactive "e")
  862. (case (org-mouse-get-gesture event)
  863. (:left (org-agenda-earlier 1))
  864. (:right (org-agenda-later 1)))))))
  865. (provide 'org-mouse)