org-mouse.el 34 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058
  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.24a
  6. ;; $Id: org-mouse.el 817 2007-02-01 00:28:02Z 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.58
  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.24
  82. ;; + minor changes to the table menu
  83. ;;
  84. ;; Version 0.23
  85. ;; + preliminary support for tables and calculation marks
  86. ;; + context menu support for org-agenda-undo & org-sort-entries
  87. ;;
  88. ;; Version 0.22
  89. ;; + handles undo support for the agenda buffer (requires org-mode >=4.58)
  90. ;;
  91. ;; Version 0.21
  92. ;; + selected text activates its context menu
  93. ;; + shift-middleclick or right-drag inserts the text from the clipboard in the form of a link
  94. ;;
  95. ;; Version 0.20
  96. ;; + the new "TODO Status" submenu replaces the "Cycle TODO" menu item
  97. ;; + the TODO menu can now list occurrences of a specific TODO keyword
  98. ;; + #+STARTUP line is now recognized
  99. ;;
  100. ;; Version 0.19
  101. ;; + added support for dragging URLs to the org-buffer
  102. ;;
  103. ;; Version 0.18
  104. ;; + added support for agenda blocks
  105. ;;
  106. ;; Version 0.17
  107. ;; + toggle checkboxes with a single click
  108. ;;
  109. ;; Version 0.16
  110. ;; + added support for checkboxes
  111. ;;
  112. ;; Version 0.15
  113. ;; + org-mode now works with the Agenda buffer as well
  114. ;;
  115. ;; Version 0.14
  116. ;; + added a menu option that converts plain list items to outline items
  117. ;;
  118. ;; Version 0.13
  119. ;; + "Insert Heading" now inserts a sibling heading if the point is
  120. ;; on "***" and a child heading otherwise
  121. ;;
  122. ;; Version 0.12
  123. ;; + compatible with Emacs 21
  124. ;; + custom agenda commands added to the main menu
  125. ;; + moving trees should now work between windows in the same frame
  126. ;;
  127. ;; Version 0.11
  128. ;; + fixed org-mouse-at-link (thanks to Carsten)
  129. ;; + removed [follow-link] bindings
  130. ;;
  131. ;; Version 0.10
  132. ;; + added a menu option to remove highlights
  133. ;; + compatible with org-mode 4.21 now
  134. ;;
  135. ;; Version 0.08:
  136. ;; + trees can be moved/promoted/demoted by dragging with the right
  137. ;; mouse button (mouse-3)
  138. ;; + small changes in the above function
  139. ;;
  140. ;; Versions 0.01 -- 0.07: (I don't remember)
  141. (require 'cl)
  142. (defvar org-mouse-plain-list-regexp "\\([ \t]*\\)\\([-+*]\\|[0-9]+[.)]\\) ")
  143. (defvar org-mouse-direct t)
  144. (defgroup org-mouse nil
  145. "Org-mouse"
  146. :tag "Org Mouse."
  147. :group 'org)
  148. (defcustom org-mouse-punctuation ":"
  149. ""
  150. :group 'org-mouse
  151. :type 'string)
  152. (defun org-mouse-re-search-line (regexp)
  153. "Searches the current line for a given regular expression."
  154. (beginning-of-line)
  155. (re-search-forward regexp (point-at-eol) t))
  156. (defun org-mouse-end-headline ()
  157. "Go to the end of current headline (ignoring tags)."
  158. (interactive)
  159. (end-of-line)
  160. (skip-chars-backward "\t ")
  161. (when (looking-back ":[A-Za-z]+:")
  162. (skip-chars-backward ":A-Za-z")
  163. (skip-chars-backward "\t ")))
  164. (defun org-mouse-show-context-menu (event prefix)
  165. (interactive "@e \nP")
  166. (if (and (= (event-click-count event) 1)
  167. (or (not mark-active)
  168. (sit-for (/ double-click-time 1000.0))))
  169. (progn
  170. (select-window (posn-window (event-start event)))
  171. (when (not (org-mouse-mark-active))
  172. (goto-char (posn-point (event-start event)))
  173. (when (not (eolp)) (save-excursion (run-hooks 'post-command-hook)))
  174. (let ((redisplay-dont-pause t))
  175. (sit-for 0)))
  176. (if (functionp org-mouse-context-menu-function)
  177. (funcall org-mouse-context-menu-function event)
  178. (mouse-major-mode-menu event prefix))
  179. )
  180. (setq this-command 'mouse-save-then-kill)
  181. (mouse-save-then-kill event)))
  182. (defun org-mouse-line-position ()
  183. "Returns :beginning :middle :end"
  184. (cond
  185. ((eolp) :end)
  186. ((org-mouse-bolp) :begin)
  187. (t :middle)))
  188. (defun org-mouse-empty-line ()
  189. (save-excursion (beginning-of-line) (looking-at "[ \t]*$")))
  190. (defun org-mouse-next-heading ()
  191. "Goes to the next heading and if there is none, it ensures that the point is at the beginning of an empty line."
  192. (unless (outline-next-heading)
  193. (beginning-of-line)
  194. (unless (org-mouse-empty-line)
  195. (end-of-line)
  196. (newline))))
  197. (defun org-mouse-insert-heading ()
  198. (interactive)
  199. (case (org-mouse-line-position)
  200. (:begin (beginning-of-line)
  201. (org-insert-heading))
  202. (t (org-mouse-next-heading)
  203. (org-insert-heading))))
  204. (defun org-mouse-timestamp-today (&optional shift units)
  205. (interactive)
  206. (flet ((org-read-date (&rest rest) (current-time)))
  207. (org-time-stamp nil))
  208. (when shift
  209. (org-timestamp-change shift units)))
  210. (defun org-mouse-keyword-menu (keywords function &optional selected itemformat)
  211. (mapcar
  212. `(lambda (keyword)
  213. (vector (cond
  214. ((functionp ,itemformat) (funcall ,itemformat keyword))
  215. ((stringp ,itemformat) (format ,itemformat keyword))
  216. (t keyword))
  217. (list 'funcall ,function keyword)
  218. :style (cond
  219. ((null ,selected) t)
  220. ((functionp ,selected) 'toggle)
  221. (t 'radio))
  222. :selected (if (functionp ,selected)
  223. (and (funcall ,selected keyword) t)
  224. (equal ,selected keyword))))
  225. keywords))
  226. (defun org-mouse-remove-match-and-spaces ()
  227. (interactive)
  228. (replace-match "")
  229. (just-one-space))
  230. (defun org-mouse-replace-match-and-surround (newtext &optional fixedcase
  231. literal string subexp)
  232. "The same as replace-match, but surrounds the replacement with spaces."
  233. (apply 'replace-match rest)
  234. (save-excursion
  235. (goto-char (match-beginning (or subexp 0)))
  236. (just-one-space)
  237. (goto-char (match-end (or subexp 0)))
  238. (just-one-space)))
  239. (defun org-mouse-keyword-replace-menu (keywords &optional group itemformat
  240. nosurround)
  241. (setq group (or group 0))
  242. (let ((replace (org-mouse-match-closure
  243. (if nosurround 'replace-match
  244. 'org-mouse-replace-match-and-surround))))
  245. (append
  246. (org-mouse-keyword-menu
  247. keywords
  248. `(lambda (keyword) (funcall ,replace keyword t t nil ,group))
  249. (match-string group)
  250. itemformat)
  251. `(["None" org-mouse-remove-match-and-spaces
  252. :style radio
  253. :selected ,(not (member (match-string group) keywords))]))))
  254. (defvar org-mouse-context-menu-function nil)
  255. (make-variable-buffer-local 'org-mouse-context-menu-function)
  256. (defun org-mouse-show-headlines ()
  257. (interactive)
  258. (let ((this-command 'org-cycle)
  259. (last-command 'org-cycle)
  260. (org-cycle-global-status nil))
  261. (org-cycle '(4))
  262. (org-cycle '(4))))
  263. (defun org-mouse-show-overview ()
  264. (interactive)
  265. (let ((org-cycle-global-status nil))
  266. (org-cycle '(4))))
  267. (defun org-mouse-set-priority (priority)
  268. (flet ((read-char-exclusive () priority))
  269. (org-priority)))
  270. (defvar org-mouse-priority-regexp "\\[#\\([A-Z]\\)\\]"
  271. "Regular expression matching the priority indicator. Differs from `org-priority-regexp' in that it doesn't contain the leading '.*?'.")
  272. (defun org-mouse-get-priority (&optional default)
  273. (save-excursion
  274. (if (org-mouse-re-search-line org-mouse-priority-regexp)
  275. (match-string 1)
  276. (when default (char-to-string org-default-priority)))))
  277. (defun org-mouse-at-link ()
  278. (and (eq (get-text-property (point) 'face) 'org-link)
  279. (save-excursion
  280. (goto-char (previous-single-property-change (point) 'face))
  281. (or (looking-at org-bracket-link-regexp)
  282. (looking-at org-angle-link-re)
  283. (looking-at org-plain-link-re)))))
  284. (defun org-mouse-delete-timestamp ()
  285. "Deletes the current timestamp as well as the preceding
  286. SCHEDULED: or DEADLINE: or ANYTHINGLIKETHIS:"
  287. (when (or (org-at-date-range-p) (org-at-timestamp-p))
  288. (replace-match "") ; delete the timestamp
  289. (skip-chars-backward " :A-Z")
  290. (when (looking-at " *[A-Z][A-Z]+:")
  291. (replace-match ""))))
  292. (defun org-mouse-looking-at (regexp skipchars &optional movechars)
  293. (save-excursion
  294. (let ((point (point)))
  295. (if (looking-at regexp) t
  296. (skip-chars-backward skipchars)
  297. (forward-char (or movechars 0))
  298. (when (looking-at regexp)
  299. (> (match-end 0) point))))))
  300. (defun org-mouse-priority-list ()
  301. (loop for priority from ?A to org-lowest-priority
  302. collect (char-to-string priority)))
  303. (defun org-mouse-tag-menu () ;todo
  304. (append
  305. (let ((tags (org-split-string (org-get-tags) ":")))
  306. (org-mouse-keyword-menu
  307. (sort (mapcar 'car (org-get-buffer-tags)) 'string-lessp)
  308. `(lambda (tag)
  309. (org-mouse-set-tags
  310. (sort (if (member tag (quote ,tags))
  311. (delete tag (quote ,tags))
  312. (cons tag (quote ,tags)))
  313. 'string-lessp)))
  314. `(lambda (tag) (member tag (quote ,tags)))
  315. ))
  316. '("--"
  317. ["Align Tags Here" (org-set-tags nil t) t]
  318. ["Align Tags in Buffer" (org-set-tags t t) t]
  319. ["Set Tags ..." (org-set-tags) t])))
  320. (defun org-mouse-set-tags (tags)
  321. (save-excursion
  322. ;; remove existing tags first
  323. (beginning-of-line)
  324. (when (org-mouse-re-search-line ":\\(\\([A-Za-z_]+:\\)+\\)")
  325. (replace-match ""))
  326. ;; set new tags if any
  327. (when tags
  328. (end-of-line)
  329. (insert " :" (mapconcat 'identity tags ":") ":")
  330. (org-set-tags nil t))))
  331. (defun org-mouse-insert-checkbox ()
  332. (interactive)
  333. (and (org-at-item-p)
  334. (goto-char (match-end 0))
  335. (unless (org-at-item-checkbox-p)
  336. (delete-horizontal-space)
  337. (insert " [ ] "))))
  338. (defun org-mouse-agenda-type (type)
  339. (case type
  340. ('tags "Tags: ")
  341. ('todo "TODO: ")
  342. ('tags-tree "Tags tree: ")
  343. ('todo-tree "TODO tree: ")
  344. ('occur-tree "Occur tree: ")
  345. (t "Agenda command ???")))
  346. (defun org-mouse-list-options-menu (alloptions &optional function)
  347. (let ((options (save-match-data
  348. (split-string (match-string-no-properties 1)))))
  349. (print options)
  350. (loop for name in alloptions
  351. collect
  352. (vector name
  353. `(progn
  354. (replace-match
  355. (mapconcat 'identity
  356. (sort (if (member ',name ',options)
  357. (delete ',name ',options)
  358. (cons ',name ',options))
  359. 'string-lessp)
  360. " ")
  361. nil nil nil 1)
  362. (when (functionp ',function) (funcall ',function)))
  363. :style 'toggle
  364. :selected (and (member name options) t)))))
  365. (defun org-mouse-clip-text (text maxlength)
  366. (if (> (length text) maxlength)
  367. (concat (substring text 0 (- maxlength 3)) "...")
  368. text))
  369. (defun org-mouse-popup-global-menu ()
  370. (popup-menu
  371. `("Main Menu"
  372. ["Show Overview" org-mouse-show-overview t]
  373. ["Show Headlines" org-mouse-show-headlines t]
  374. ["Show All" show-all t]
  375. ["Remove Highlights" org-remove-occur-highlights
  376. :visible org-occur-highlights]
  377. "--"
  378. ["Check Deadlines"
  379. (if (functionp 'org-check-deadlines-and-todos)
  380. (org-check-deadlines-and-todos org-deadline-warning-days)
  381. (org-check-deadlines org-deadline-warning-days)) t]
  382. ["Check TODOs" org-show-todo-tree t]
  383. ("Check Tags"
  384. ,@(org-mouse-keyword-menu
  385. (sort (mapcar 'car (org-get-buffer-tags)) 'string-lessp)
  386. '(lambda (tag) (org-tags-sparse-tree nil tag)))
  387. "--"
  388. ["Custom Tag ..." org-tags-sparse-tree t])
  389. ["Check Phrase ..." org-occur]
  390. "--"
  391. ["Display Agenda" org-agenda-list t]
  392. ["Display Timeline" org-timeline t]
  393. ["Display TODO List" org-todo-list t]
  394. ("Display Tags"
  395. ,@(org-mouse-keyword-menu
  396. (sort (mapcar 'car (org-get-buffer-tags)) 'string-lessp)
  397. '(lambda (tag) (org-tags-view nil tag)))
  398. "--"
  399. ["Custom Tag ..." org-tags-view t])
  400. ["Display Calendar" org-goto-calendar t]
  401. "--"
  402. ,@(org-mouse-keyword-menu
  403. (mapcar 'car org-agenda-custom-commands)
  404. '(lambda (key)
  405. (eval `(flet ((read-char-exclusive () (string-to-char ,key)))
  406. (org-agenda nil))))
  407. nil
  408. '(lambda (key)
  409. (let ((entry (assoc key org-agenda-custom-commands)))
  410. (org-mouse-clip-text
  411. (cond
  412. ((stringp (nth 1 entry)) (nth 1 entry))
  413. ((stringp (nth 2 entry))
  414. (concat (org-mouse-agenda-type (nth 1 entry))
  415. (nth 2 entry)))
  416. (t "Agenda Command '%s'"))
  417. 30))))
  418. ;; )
  419. "--"
  420. ["Delete Blank Lines" delete-blank-lines
  421. :visible (org-mouse-empty-line)]
  422. ["Insert Checkbox" org-mouse-insert-checkbox
  423. :visible (and (org-at-item-p) (not (org-at-item-checkbox-p)))]
  424. ["Insert Checkboxes"
  425. (org-mouse-for-each-item 'org-mouse-insert-checkbox)
  426. :visible (and (org-at-item-p) (not (org-at-item-checkbox-p)))]
  427. ["Plain List to Outline" org-mouse-transform-to-outline
  428. :visible (org-at-item-p)])))
  429. (defun org-mouse-get-context (contextlist context)
  430. (let ((contextdata (assq context contextlist)))
  431. (when contextdata
  432. (save-excursion
  433. (goto-char (second contextdata))
  434. (re-search-forward ".*" (third contextdata))))))
  435. (defun org-mouse-for-each-item (function)
  436. (save-excursion
  437. (ignore-errors
  438. (while t (org-previous-item)))
  439. (ignore-errors
  440. (while t
  441. (funcall function)
  442. (org-next-item)))))
  443. (defun org-mouse-bolp ()
  444. "Returns true if there only spaces, tabs, and '*', between the beginning of line and the point"
  445. (save-excursion
  446. (skip-chars-backward " \t*") (bolp)))
  447. (defun org-mouse-insert-item (text)
  448. (case (org-mouse-line-position)
  449. (:begin ; insert before
  450. (beginning-of-line)
  451. (looking-at "[ \t]*")
  452. (open-line 1)
  453. (indent-to (- (match-end 0) (match-beginning 0)))
  454. (insert "+ "))
  455. (:middle ; insert after
  456. (end-of-line)
  457. (newline t)
  458. (indent-relative)
  459. (insert "+ "))
  460. (:end ; insert text here
  461. (skip-chars-backward " \t")
  462. (kill-region (point) (point-at-eol))
  463. (unless (looking-back org-mouse-punctuation)
  464. (insert (concat org-mouse-punctuation " ")))))
  465. (insert text)
  466. (beginning-of-line))
  467. (defadvice dnd-insert-text (around org-mouse-dnd-insert-text activate)
  468. (if (eq major-mode 'org-mode)
  469. (org-mouse-insert-item text)
  470. ad-do-it))
  471. (defadvice dnd-open-file (around org-mouse-dnd-open-file activate)
  472. (if (eq major-mode 'org-mode)
  473. (org-mouse-insert-item uri)
  474. ad-do-it))
  475. (defun org-mouse-match-closure (function)
  476. (let ((match (match-data t)))
  477. `(lambda (&rest rest)
  478. (save-match-data
  479. (set-match-data ',match)
  480. (apply ',function rest)))))
  481. (defun org-mouse-todo-keywords ()
  482. (if (boundp 'org-todo-keywords-1) org-todo-keywords-1 org-todo-keywords))
  483. (defun org-mouse-match-todo-keyword ()
  484. (save-excursion
  485. (org-back-to-heading)
  486. (if (looking-at outline-regexp) (goto-char (match-end 0)))
  487. (or (looking-at (concat " +" org-todo-regexp " *"))
  488. (looking-at " \\( *\\)"))))
  489. (defun org-mouse-yank-link (click)
  490. (interactive "e")
  491. ;; Give temporary modes such as isearch a chance to turn off.
  492. (run-hooks 'mouse-leave-buffer-hook)
  493. (mouse-set-point click)
  494. (setq mouse-selection-click-count 0)
  495. (delete-horizontal-space)
  496. (insert-for-yank (concat " [[" (current-kill 0) "]] ")))
  497. (defun org-mouse-context-menu (&optional event)
  498. (let ((stamp-prefixes (list org-deadline-string org-scheduled-string))
  499. (contextlist (org-context)))
  500. (flet ((get-context (context) (org-mouse-get-context contextlist context)))
  501. (cond
  502. ((org-mouse-mark-active)
  503. (let ((region-string (buffer-substring (region-beginning) (region-end))))
  504. (popup-menu
  505. `(nil
  506. ["Sparse Tree" (org-occur ',region-string)]
  507. ["Find in Buffer" (occur ',region-string)]
  508. ["Grep in Current Dir"
  509. (grep (format "grep -rnH -e '%s' *" ',region-string))]
  510. ["Grep in Parent Dir"
  511. (grep (format "grep -rnH -e '%s' ../*" ',region-string))]
  512. "--"
  513. ["Convert to Link"
  514. (progn (save-excursion (goto-char (region-beginning)) (insert "[["))
  515. (save-excursion (goto-char (region-end)) (insert "]]")))]
  516. ["Insert Link Here" (org-mouse-yank-link ',event)]))))
  517. ((save-excursion (beginning-of-line) (looking-at "#\\+STARTUP: \\(.*\\)"))
  518. (popup-menu
  519. `(nil
  520. ,@(org-mouse-list-options-menu (mapcar 'car org-startup-options)
  521. 'org-mode-restart))))
  522. ((or (eolp)
  523. (and (looking-at "\\( \\|\t\\)\\(+:[0-9a-zA-Z_:]+\\)?\\( \\|\t\\)+$")
  524. (looking-back " \\|\t")))
  525. (org-mouse-popup-global-menu))
  526. ((get-context :checkbox)
  527. (popup-menu
  528. '(nil
  529. ["Toggle" org-toggle-checkbox t]
  530. ["Remove" org-mouse-remove-match-and-spaces t]
  531. ""
  532. ["All Clear" (org-mouse-for-each-item
  533. (lambda ()
  534. (when (save-excursion (org-at-item-checkbox-p))
  535. (replace-match "[ ]"))))]
  536. ["All Set" (org-mouse-for-each-item
  537. (lambda ()
  538. (when (save-excursion (org-at-item-checkbox-p))
  539. (replace-match "[X]"))))]
  540. ["All Toggle" (org-mouse-for-each-item 'org-toggle-checkbox) t]
  541. ["All Remove" (org-mouse-for-each-item
  542. (lambda ()
  543. (when (save-excursion (org-at-item-checkbox-p))
  544. (org-mouse-remove-match-and-spaces))))]
  545. )))
  546. ((and (org-mouse-looking-at "\\b\\w+" "a-zA-Z0-9_")
  547. (member (match-string 0) (org-mouse-todo-keywords)))
  548. (popup-menu
  549. `(nil
  550. ,@(org-mouse-keyword-replace-menu (org-mouse-todo-keywords))
  551. "--"
  552. ["Check TODOs" org-show-todo-tree t]
  553. ["List all TODO keywords" org-todo-list t]
  554. [,(format "List only %s" (match-string 0))
  555. (org-todo-list (match-string 0)) t]
  556. )))
  557. ((and (org-mouse-looking-at "\\b[A-Z]+:" "A-Z")
  558. (member (match-string 0) stamp-prefixes))
  559. (popup-menu
  560. `(nil
  561. ,@(org-mouse-keyword-replace-menu stamp-prefixes)
  562. "--"
  563. ["Check Deadlines" org-check-deadlines t]
  564. )))
  565. ((org-mouse-looking-at org-mouse-priority-regexp "[]A-Z#") ; priority
  566. (popup-menu `(nil ,@(org-mouse-keyword-replace-menu
  567. (org-mouse-priority-list) 1 "Priority %s" t))))
  568. ((org-mouse-at-link)
  569. (popup-menu
  570. '(nil
  571. ["Open" org-open-at-point t]
  572. ["Open in Emacs" (org-open-at-point t) t]
  573. "--"
  574. ["Copy link" (kill-new (match-string 0))]
  575. ["Cut link"
  576. (progn
  577. (kill-region (match-beginning 0) (match-end 0))
  578. (just-one-space))]
  579. "--"
  580. ["Grep for TODOs"
  581. (grep (format "grep -nH -i 'todo\\|fixme' %s*" (match-string 2)))]
  582. ; ["Paste file link" ((insert "file:") (yank))]
  583. )))
  584. ((org-mouse-looking-at ":\\([A-Za-z0-9_]+\\):" "A-Za-z0-9_" -1) ;tags
  585. (popup-menu
  586. `(nil
  587. [,(format "Display '%s'" (match-string 1))
  588. (org-tags-view nil ,(match-string 1))]
  589. [,(format "Sparse Tree '%s'" (match-string 1))
  590. (org-tags-sparse-tree nil ,(match-string 1))]
  591. "--"
  592. ,@(org-mouse-tag-menu))))
  593. ((org-at-timestamp-p)
  594. (popup-menu
  595. '(nil
  596. ["Show Day" org-open-at-point t]
  597. ["Change Timestamp" org-time-stamp t]
  598. ["Delete Timestamp" (org-mouse-delete-timestamp) t]
  599. ["Compute Time Range" org-evaluate-time-range (org-at-date-range-p)]
  600. "--"
  601. ["Set for Today" org-mouse-timestamp-today]
  602. ["Set for Tomorrow" (org-mouse-timestamp-today 1 'day)]
  603. ["Set in 1 Week" (org-mouse-timestamp-today 7 'day)]
  604. ["Set in 2 Weeks" (org-mouse-timestamp-today 14 'day)]
  605. ["Set in a Month" (org-mouse-timestamp-today 1 'month)]
  606. "--"
  607. ["+ 1 Day" (org-timestamp-change 1 'day)]
  608. ["+ 1 Week" (org-timestamp-change 7 'day)]
  609. ["+ 1 Month" (org-timestamp-change 1 'month)]
  610. "--"
  611. ["- 1 Day" (org-timestamp-change -1 'day)]
  612. ["- 1 Week" (org-timestamp-change -7 'day)]
  613. ["- 1 Month" (org-timestamp-change -1 'month)])))
  614. ((get-context :table-special)
  615. (let ((mdata (match-data)))
  616. (incf (car mdata) 2)
  617. (store-match-data mdata))
  618. (message "match: %S" (match-string 0))
  619. (popup-menu `(nil ,@(org-mouse-keyword-replace-menu
  620. '(" " "!" "^" "_" "$" "#" "*" "'") 0
  621. (lambda (mark)
  622. (case (string-to-char mark)
  623. (? "( ) Nothing Special")
  624. (?! "(!) Column Names")
  625. (?^ "(^) Field Names Above")
  626. (?_ "(^) Field Names Below")
  627. (?$ "($) Formula Parameters")
  628. (?# "(#) Recalculation: Auto")
  629. (?* "(*) Recalculation: Manual")
  630. (?' "(') Recalculation: None"))) t))))
  631. ((assq :table contextlist)
  632. (popup-menu
  633. '(nil
  634. ["Align Table" org-ctrl-c-ctrl-c]
  635. ["Blank Field" org-table-blank-field]
  636. ["Edit Field" org-table-edit-field]
  637. "--"
  638. ("Column"
  639. ["Move Column Left" org-metaleft]
  640. ["Move Column Right" org-metaright]
  641. ["Delete Column" org-shiftmetaleft]
  642. ["Insert Column" org-shiftmetaright]
  643. "--"
  644. ["Enable Narrowing" (setq org-table-limit-column-width (not org-table-limit-column-width)) :selected org-table-limit-column-width :style toggle])
  645. ("Row"
  646. ["Move Row Up" org-metaup]
  647. ["Move Row Down" org-metadown]
  648. ["Delete Row" org-shiftmetaup]
  649. ["Insert Row" org-shiftmetadown]
  650. ["Sort lines in region" org-table-sort-lines (org-at-table-p)]
  651. "--"
  652. ["Insert Hline" org-table-insert-hline])
  653. ("Rectangle"
  654. ["Copy Rectangle" org-copy-special]
  655. ["Cut Rectangle" org-cut-special]
  656. ["Paste Rectangle" org-paste-special]
  657. ["Fill Rectangle" org-table-wrap-region])
  658. "--"
  659. ["Set Column Formula" org-table-eval-formula]
  660. ["Set Field Formula" (org-table-eval-formula '(4))]
  661. ["Edit Formulas" org-table-edit-formulas]
  662. "--"
  663. ["Recalculate Line" org-table-recalculate]
  664. ["Recalculate All" (org-table-recalculate '(4))]
  665. ["Iterate All" (org-table-recalculate '(16))]
  666. "--"
  667. ["Toggle Recalculate Mark" org-table-rotate-recalc-marks]
  668. ["Sum Column/Rectangle" org-table-sum
  669. :active (or (org-at-table-p) (org-region-active-p))]
  670. ["Field Info" org-table-field-info]
  671. ["Debug Formulas"
  672. (setq org-table-formula-debug (not org-table-formula-debug))
  673. :style toggle :selected org-table-formula-debug]
  674. )))
  675. ((and (assq :headline contextlist) (not (eolp)))
  676. (let ((priority (org-mouse-get-priority t)))
  677. (popup-menu
  678. `("Headline Menu"
  679. ("Tags and Priorities"
  680. ,@(org-mouse-keyword-menu
  681. (org-mouse-priority-list)
  682. '(lambda (keyword)
  683. (org-mouse-set-priority (string-to-char keyword)))
  684. priority "Priority %s")
  685. "--"
  686. ,@(org-mouse-tag-menu))
  687. ("TODO Status"
  688. ,@(progn (org-mouse-match-todo-keyword)
  689. (org-mouse-keyword-replace-menu (org-mouse-todo-keywords)
  690. 1)))
  691. ["Show Tags"
  692. (with-current-buffer org-mouse-main-buffer (org-agenda-show-tags))
  693. :visible (not org-mouse-direct)]
  694. ["Show Priority"
  695. (with-current-buffer org-mouse-main-buffer (org-agenda-show-priority))
  696. :visible (not org-mouse-direct)]
  697. ,@(if org-mouse-direct '("--") nil)
  698. ["New Heading" org-mouse-insert-heading :visible org-mouse-direct]
  699. ["Set Deadline"
  700. (progn (org-mouse-end-headline) (insert " ") (org-deadline))
  701. :active (not (save-excursion
  702. (org-mouse-re-search-line org-deadline-regexp)))]
  703. ["Schedule Task"
  704. (progn (org-mouse-end-headline) (insert " ") (org-schedule))
  705. :active (not (save-excursion
  706. (org-mouse-re-search-line org-scheduled-regexp)))]
  707. ["Insert Timestamp"
  708. (progn (org-mouse-end-headline) (insert " ") (org-time-stamp nil)) t]
  709. ; ["Timestamp (inactive)" org-time-stamp-inactive t]
  710. "--"
  711. ["Archive Subtree" org-archive-subtree]
  712. ["Cut Subtree" org-cut-special]
  713. ["Copy Subtree" org-copy-special]
  714. ["Paste Subtree" org-paste-special :visible org-mouse-direct]
  715. ("Sort Children"
  716. ["Alphabetically" (org-sort-entries nil ?a)]
  717. ["Numerically" (org-sort-entries nil ?n)]
  718. ["By Time/Date" (org-sort-entries nil ?t)]
  719. "--"
  720. ["Reverse Alphabetically" (org-sort-entries nil ?A)]
  721. ["Reverse Numerically" (org-sort-entries nil ?N)]
  722. ["Reverse By Time/Date" (org-sort-entries nil ?T)])
  723. "--"
  724. ["Move Trees" org-mouse-move-tree :active nil]
  725. ))))
  726. (t
  727. (org-mouse-popup-global-menu))))))
  728. ;; (defun org-mouse-at-regexp (regexp)
  729. ;; (save-excursion
  730. ;; (let ((point (point))
  731. ;; (bol (progn (beginning-of-line) (point)))
  732. ;; (eol (progn (end-of-line) (point))))
  733. ;; (goto-char point)
  734. ;; (re-search-backward regexp bol 1)
  735. ;; (and (not (eolp))
  736. ;; (progn (forward-char)
  737. ;; (re-search-forward regexp eol t))
  738. ;; (<= (match-beginning 0) point)))))
  739. (defun org-mouse-mark-active ()
  740. (and mark-active transient-mark-mode))
  741. (defun org-mouse-in-region-p (pos)
  742. (and (org-mouse-mark-active)
  743. (>= pos (region-beginning))
  744. (< pos (region-end))))
  745. (defun org-mouse-down-mouse (event)
  746. (interactive "e")
  747. (setq this-command last-command)
  748. (unless (and (= 1 (event-click-count event))
  749. (org-mouse-in-region-p (posn-point (event-start event))))
  750. (mouse-drag-region event)))
  751. (add-hook 'org-mode-hook
  752. '(lambda ()
  753. (setq org-mouse-context-menu-function 'org-mouse-context-menu)
  754. ; (define-key org-mouse-map [follow-link] 'mouse-face)
  755. (define-key org-mouse-map (if (featurep 'xemacs) [button3] [mouse-3]) nil)
  756. (define-key org-mode-map [mouse-3] 'org-mouse-show-context-menu)
  757. (define-key org-mode-map [down-mouse-1] 'org-mouse-down-mouse)
  758. (define-key org-mouse-map [C-drag-mouse-1] 'org-mouse-move-tree)
  759. (define-key org-mouse-map [C-down-mouse-1] 'org-mouse-move-tree-start)
  760. (define-key org-mode-map [S-mouse-2] 'org-mouse-yank-link)
  761. (define-key org-mode-map [drag-mouse-3] 'org-mouse-yank-link)
  762. (define-key org-mouse-map [drag-mouse-3] 'org-mouse-move-tree)
  763. (define-key org-mouse-map [down-mouse-3] 'org-mouse-move-tree-start)
  764. (font-lock-add-keywords nil
  765. `((,outline-regexp
  766. 0 `(face org-link mouse-face highlight keymap ,org-mouse-map)
  767. 'prepend)
  768. ("^[ \t]*\\([-+*]\\|[0-9]+[.)]\\) +"
  769. (1 `(face org-link keymap ,org-mouse-map mouse-face highlight) 'prepend))
  770. ("^[ \t]*\\([-+*]\\|[0-9]+[.)]\\) +\\(\\[[ X]\\]\\)"
  771. (2 `(face bold keymap ,org-mouse-map mouse-face highlight) t)))
  772. t)
  773. (defadvice org-open-at-point (around org-mouse-open-at-point activate)
  774. (let ((context (org-context)))
  775. (cond
  776. ((assq :headline-stars context) (org-cycle))
  777. ((assq :checkbox context) (org-toggle-checkbox))
  778. ((assq :item-bullet context)
  779. (let ((org-cycle-include-plain-lists t)) (org-cycle)))
  780. (t ad-do-it))))))
  781. (defun org-mouse-move-tree-start (event)
  782. (interactive "e")
  783. (message "Same line: promote/demote, (***):move before, (text): make a child"))
  784. (defun org-mouse-make-marker (position)
  785. (with-current-buffer (window-buffer (posn-window position))
  786. (copy-marker (posn-point position))))
  787. (defun org-mouse-move-tree (event)
  788. ;; todo: handle movements between different buffers
  789. (interactive "e")
  790. (save-excursion
  791. (let* ((start (org-mouse-make-marker (event-start event)))
  792. (end (org-mouse-make-marker (event-end event)))
  793. (sbuf (marker-buffer start))
  794. (ebuf (marker-buffer end)))
  795. (when (and sbuf ebuf)
  796. (set-buffer sbuf)
  797. (goto-char start)
  798. (org-back-to-heading)
  799. (if (and (eq sbuf ebuf)
  800. (equal
  801. (point)
  802. (save-excursion (goto-char end) (org-back-to-heading) (point))))
  803. ;; if the same line then promote/demote
  804. (if (>= end start) (org-demote-subtree) (org-promote-subtree))
  805. ;; if different lines then move
  806. (org-cut-subtree)
  807. (set-buffer ebuf)
  808. (goto-char end)
  809. (org-back-to-heading)
  810. (when (and (eq sbuf ebuf)
  811. (equal
  812. (point)
  813. (save-excursion (goto-char start)
  814. (org-back-to-heading) (point))))
  815. (outline-end-of-subtree)
  816. (end-of-line)
  817. (if (eobp) (newline) (forward-char)))
  818. (when (looking-at outline-regexp)
  819. (let ((level (- (match-end 0) (match-beginning 0))))
  820. (when (> end (match-end 0))
  821. (outline-end-of-subtree)
  822. (end-of-line)
  823. (if (eobp) (newline) (forward-char))
  824. (setq level (1+ level)))
  825. (org-paste-subtree level)
  826. (save-excursion
  827. (outline-end-of-subtree)
  828. (when (bolp) (delete-char -1))))))))))
  829. (defun org-mouse-transform-to-outline ()
  830. (interactive)
  831. (org-back-to-heading)
  832. (let ((minlevel 1000)
  833. (replace-text (concat (match-string 0) "* ")))
  834. (beginning-of-line 2)
  835. (save-excursion
  836. (while (not (or (eobp) (looking-at outline-regexp)))
  837. (when (looking-at org-mouse-plain-list-regexp)
  838. (setq minlevel (min minlevel (- (match-end 1) (match-beginning 1)))))
  839. (forward-line)))
  840. (while (not (or (eobp) (looking-at outline-regexp)))
  841. (when (and (looking-at org-mouse-plain-list-regexp)
  842. (eq minlevel (- (match-end 1) (match-beginning 1))))
  843. (replace-match replace-text))
  844. (forward-line))))
  845. (defun org-mouse-do-remotely (command)
  846. ; (org-agenda-check-no-diary)
  847. (when (get-text-property (point) 'org-marker)
  848. (let* ((anticol (- (point-at-eol) (point)))
  849. (marker (get-text-property (point) 'org-marker))
  850. (buffer (marker-buffer marker))
  851. (pos (marker-position marker))
  852. (hdmarker (get-text-property (point) 'org-hd-marker))
  853. (buffer-read-only nil)
  854. (newhead "--- removed ---")
  855. (org-mouse-direct nil)
  856. (org-mouse-main-buffer (current-buffer)))
  857. (when (eq (with-current-buffer buffer major-mode) 'org-mode)
  858. (let ((endmarker (save-excursion
  859. (set-buffer buffer)
  860. (outline-end-of-subtree)
  861. (forward-char 1)
  862. (copy-marker (point)))))
  863. (org-with-remote-undo buffer
  864. (with-current-buffer buffer
  865. (widen)
  866. (goto-char pos)
  867. (org-show-hidden-entry)
  868. (save-excursion
  869. (and (outline-next-heading)
  870. (org-flag-heading nil))) ; show the next heading
  871. (org-back-to-heading)
  872. (setq marker (copy-marker (point)))
  873. (goto-char (max (point-at-bol) (- (point-at-eol) anticol)))
  874. (funcall command)
  875. (message "_cmd: %S" _cmd)
  876. (message "this-command: %S" this-command)
  877. (unless (eq (marker-position marker) (marker-position endmarker))
  878. (setq newhead (org-get-heading))))
  879. (beginning-of-line 1)
  880. (save-excursion
  881. (org-agenda-change-all-lines newhead hdmarker 'fixface))))
  882. t))))
  883. (defun org-mouse-agenda-context-menu (&optional event)
  884. (or (org-mouse-do-remotely 'org-mouse-context-menu)
  885. (popup-menu
  886. '("Agenda"
  887. ("Agenda Files")
  888. "--"
  889. ["Undo" (progn (message "last command: %S" last-command) (setq this-command 'org-agenda-undo) (org-agenda-undo))
  890. :visible (if (eq last-command 'org-agenda-undo)
  891. org-agenda-pending-undo-list
  892. org-agenda-undo-list)]
  893. ["Rebuild Buffer" org-agenda-redo t]
  894. ["New Diary Entry"
  895. org-agenda-diary-entry (org-agenda-check-type nil 'agenda 'timeline) t]
  896. "--"
  897. ["Goto Today" org-agenda-goto-today
  898. (org-agenda-check-type nil 'agenda 'timeline) t]
  899. ["Display Calendar" org-agenda-goto-calendar
  900. (org-agenda-check-type nil 'agenda 'timeline) t]
  901. ("Calendar Commands"
  902. ["Phases of the Moon" org-agenda-phases-of-moon
  903. (org-agenda-check-type nil 'agenda 'timeline)]
  904. ["Sunrise/Sunset" org-agenda-sunrise-sunset
  905. (org-agenda-check-type nil 'agenda 'timeline)]
  906. ["Holidays" org-agenda-holidays
  907. (org-agenda-check-type nil 'agenda 'timeline)]
  908. ["Convert" org-agenda-convert-date
  909. (org-agenda-check-type nil 'agenda 'timeline)]
  910. "--"
  911. ["Create iCalendar file" org-export-icalendar-combine-agenda-files t])
  912. "--"
  913. ["Day View" org-agenda-day-view
  914. :active (org-agenda-check-type nil 'agenda)
  915. :style radio :selected (equal org-agenda-ndays 1)]
  916. ["Week View" org-agenda-week-view
  917. :active (org-agenda-check-type nil 'agenda)
  918. :style radio :selected (equal org-agenda-ndays 7)]
  919. "--"
  920. ["Show Logbook entries" org-agenda-log-mode
  921. :style toggle :selected org-agenda-show-log
  922. :active (org-agenda-check-type nil 'agenda 'timeline)]
  923. ["Include Diary" org-agenda-toggle-diary
  924. :style toggle :selected org-agenda-include-diary
  925. :active (org-agenda-check-type nil 'agenda)]
  926. ["Use Time Grid" org-agenda-toggle-time-grid
  927. :style toggle :selected org-agenda-use-time-grid
  928. :active (org-agenda-check-type nil 'agenda)]
  929. ["Follow Mode" org-agenda-follow-mode
  930. :style toggle :selected org-agenda-follow-mode]
  931. "--"
  932. ["Quit" org-agenda-quit t]
  933. ["Exit and Release Buffers" org-agenda-exit t]
  934. ))))
  935. (defun org-mouse-get-gesture (event)
  936. (let ((startxy (posn-x-y (event-start event)))
  937. (endxy (posn-x-y (event-end event))))
  938. (if (< (car startxy) (car endxy)) :right :left)))
  939. ; (setq org-agenda-mode-hook nil)
  940. (add-hook 'org-agenda-mode-hook
  941. '(lambda ()
  942. (setq org-mouse-context-menu-function 'org-mouse-agenda-context-menu)
  943. (define-key org-agenda-keymap
  944. (if (featurep 'xemacs) [button3] [mouse-3])
  945. 'org-mouse-show-context-menu)
  946. (define-key org-agenda-keymap [down-mouse-3] 'org-mouse-move-tree-start)
  947. (define-key org-agenda-keymap [C-mouse-4] 'org-agenda-earlier)
  948. (define-key org-agenda-keymap [C-mouse-5] 'org-agenda-later)
  949. (define-key org-agenda-keymap [drag-mouse-3]
  950. '(lambda (event) (interactive "e")
  951. (case (org-mouse-get-gesture event)
  952. (:left (org-agenda-earlier 1))
  953. (:right (org-agenda-later 1)))))))
  954. (provide 'org-mouse)