diary-lib.el 116 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632
  1. ;;; diary-lib.el --- diary functions
  2. ;; Copyright (C) 1989-1990, 1992-1995, 2001-2012
  3. ;; Free Software Foundation, Inc.
  4. ;; Author: Edward M. Reingold <reingold@cs.uiuc.edu>
  5. ;; Maintainer: Glenn Morris <rgm@gnu.org>
  6. ;; Keywords: calendar
  7. ;; This file is part of GNU Emacs.
  8. ;; GNU Emacs is free software: you can redistribute it and/or modify
  9. ;; it under the terms of the GNU General Public License as published by
  10. ;; the Free Software Foundation, either version 3 of the License, or
  11. ;; (at your option) any later version.
  12. ;; GNU Emacs is distributed in the hope that it will be useful,
  13. ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. ;; GNU General Public License for more details.
  16. ;; You should have received a copy of the GNU General Public License
  17. ;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
  18. ;;; Commentary:
  19. ;; See calendar.el.
  20. ;;; Code:
  21. (require 'calendar)
  22. (eval-and-compile (load "diary-loaddefs" nil t))
  23. (defgroup diary nil
  24. "Emacs diary."
  25. :prefix "diary-"
  26. :group 'calendar)
  27. (defcustom diary-include-string "#include"
  28. "The string indicating inclusion of another file of diary entries.
  29. See the documentation for the function `diary-include-other-diary-files'."
  30. :type 'string
  31. :group 'diary)
  32. (defcustom diary-list-include-blanks nil
  33. "If nil, do not include days with no diary entry in the list of diary entries.
  34. Such days will then not be shown in the fancy diary buffer, even if they
  35. are holidays."
  36. :type 'boolean
  37. :group 'diary)
  38. (defcustom diary-face 'diary
  39. "Face name to use for diary entries."
  40. :type 'face
  41. :group 'calendar-faces)
  42. (make-obsolete-variable 'diary-face "customize the face `diary' instead."
  43. "23.1")
  44. (defface diary-anniversary '((t :inherit font-lock-keyword-face))
  45. "Face used for anniversaries in the fancy diary display."
  46. :version "22.1"
  47. :group 'calendar-faces)
  48. (defface diary-time '((t :inherit font-lock-variable-name-face))
  49. "Face used for times of day in the fancy diary display."
  50. :version "22.1"
  51. :group 'calendar-faces)
  52. (defface diary-button '((((type pc) (class color))
  53. (:foreground "lightblue")))
  54. "Face used for buttons in the fancy diary display."
  55. :version "22.1"
  56. :group 'calendar-faces)
  57. (define-obsolete-face-alias 'diary-button-face 'diary-button "22.1")
  58. ;; Face markup of calendar and diary displays: Any entry line that
  59. ;; ends with [foo:value] where foo is a face attribute (except :box
  60. ;; :stipple) or with [face:blah] tags, will have these values applied
  61. ;; to the calendar and fancy diary displays. These attributes "stack"
  62. ;; on calendar displays. File-wide attributes can be defined as
  63. ;; follows: the first line matching "^# [tag:value]" defines the value
  64. ;; for that particular tag.
  65. (defcustom diary-face-attrs
  66. '((" *\\[foreground:\\([-a-z]+\\)\\]$" 1 :foreground string)
  67. (" *\\[background:\\([-a-z]+\\)\\]$" 1 :background string)
  68. (" *\\[width:\\([-a-z]+\\)\\]$" 1 :width symbol)
  69. (" *\\[height:\\([.0-9]+\\)\\]$" 1 :height int)
  70. (" *\\[weight:\\([-a-z]+\\)\\]$" 1 :weight symbol)
  71. (" *\\[slant:\\([-a-z]+\\)\\]$" 1 :slant symbol)
  72. (" *\\[underline:\\([-a-z]+\\)\\]$" 1 :underline stringtnil)
  73. (" *\\[overline:\\([-a-z]+\\)\\]$" 1 :overline stringtnil)
  74. (" *\\[strike-through:\\([-a-z]+\\)\\]$" 1 :strike-through stringtnil)
  75. (" *\\[inverse-video:\\([-a-z]+\\)\\]$" 1 :inverse-video tnil)
  76. (" *\\[face:\\([-0-9a-z]+\\)\\]$" 1 :face string)
  77. (" *\\[font:\\([-a-z0-9]+\\)\\]$" 1 :font string)
  78. ;; Unsupported.
  79. ;;; (" *\\[box:\\([-a-z]+\\)\\]$" 1 :box)
  80. ;;; (" *\\[stipple:\\([-a-z]+\\)\\]$" 1 :stipple)
  81. )
  82. "Alist of (REGEXP SUBEXP ATTRIBUTE TYPE) elements.
  83. This is used by `diary-pull-attrs' to fontify certain diary
  84. elements. REGEXP is a regular expression to for, and SUBEXP is
  85. the numbered sub-expression to extract. `diary-glob-file-regexp-prefix'
  86. is pre-pended to REGEXP for file-wide specifiers. ATTRIBUTE
  87. specifies which face attribute (e.g. `:foreground') to modify, or
  88. that this is a face (`:face') to apply. TYPE is the type of
  89. attribute being applied. Available TYPES (see `diary-attrtype-convert')
  90. are: `string', `symbol', `int', `tnil', `stringtnil.'"
  91. :type '(repeat (list (string :tag "Regular expression")
  92. (integer :tag "Sub-expression")
  93. (symbol :tag "Attribute (e.g. :foreground)")
  94. (choice (const string :tag "A string")
  95. (const symbol :tag "A symbol")
  96. (const int :tag "An integer")
  97. (const tnil :tag "`t' or `nil'")
  98. (const stringtnil
  99. :tag "A string, `t', or `nil'"))))
  100. :group 'diary)
  101. (defcustom diary-glob-file-regexp-prefix "^\\#"
  102. "Regular expression pre-pended to `diary-face-attrs' for file-wide specifiers."
  103. :type 'regexp
  104. :group 'diary)
  105. (defcustom diary-file-name-prefix nil
  106. "Non-nil means prefix each diary entry with the name of the file defining it."
  107. :type 'boolean
  108. :group 'diary)
  109. (defcustom diary-file-name-prefix-function 'identity
  110. "The function that will take a diary file name and return the desired prefix."
  111. :type 'function
  112. :group 'diary)
  113. (define-obsolete-variable-alias 'sexp-diary-entry-symbol
  114. 'diary-sexp-entry-symbol "23.1")
  115. (defcustom diary-sexp-entry-symbol "%%"
  116. "The string used to indicate a sexp diary entry in `diary-file'.
  117. See the documentation for the function `diary-list-sexp-entries'."
  118. :type 'string
  119. :group 'diary)
  120. (defcustom diary-comment-start nil
  121. "String marking the start of a comment in the diary, or nil.
  122. Nil means there are no comments. The diary does not display
  123. parts of entries that are inside comments. You can use comments
  124. for whatever you like, e.g. for meta-data that packages such as
  125. `appt.el' can use. Comments may not span multiple lines, and there
  126. can be only one comment on any line.
  127. See also `diary-comment-end'."
  128. :version "24.1"
  129. :type '(choice (const :tag "No comment" nil) string)
  130. :group 'diary)
  131. (defcustom diary-comment-end ""
  132. "String marking the end of a comment in the diary.
  133. The empty string means comments finish at the end of a line.
  134. See also `diary-comment-start'."
  135. :version "24.1"
  136. :type 'string
  137. :group 'diary)
  138. (defcustom diary-hook nil
  139. "List of functions called after the display of the diary.
  140. Used for example by the appointment package - see `appt-activate'."
  141. :type 'hook
  142. :group 'diary)
  143. (define-obsolete-variable-alias 'diary-display-hook 'diary-display-function
  144. "23.1")
  145. (defcustom diary-display-function 'diary-fancy-display
  146. "Function used to display the diary.
  147. The two standard options are `diary-fancy-display' and `diary-simple-display'.
  148. For historical reasons, `nil' is the same as `diary-simple-display'
  149. \(so you must use `ignore' for no display). Also for historical
  150. reasons, this variable can be a list of functions to run. These
  151. uses are not recommended and may be removed at some point.
  152. When this function is called, the variable `diary-entries-list'
  153. is a list, in order by date, of all relevant diary entries in the
  154. form of ((MONTH DAY YEAR) STRING), where string is the diary
  155. entry for the given date. This can be used, for example, to
  156. produce a different buffer for display (perhaps combined with
  157. holidays), or hard copy output."
  158. :type '(choice (const diary-fancy-display :tag "Fancy display")
  159. (const diary-simple-display :tag "Basic display")
  160. (const ignore :tag "No display")
  161. (const nil :tag "Obsolete way to choose basic display")
  162. (hook :tag "Obsolete form with list of display functions"))
  163. :initialize 'custom-initialize-default
  164. :set 'diary-set-maybe-redraw
  165. :version "23.2" ; simple->fancy
  166. :group 'diary)
  167. (define-obsolete-variable-alias 'list-diary-entries-hook
  168. 'diary-list-entries-hook "23.1")
  169. (defcustom diary-list-entries-hook nil
  170. "List of functions called after diary file is culled for relevant entries.
  171. You might wish to add `diary-include-other-diary-files', in which case
  172. you will probably also want to add `diary-mark-included-diary-files' to
  173. `diary-mark-entries-hook'. For example, you could use
  174. (setq diary-display-function 'diary-fancy-display)
  175. (add-hook 'diary-list-entries-hook 'diary-include-other-diary-files)
  176. (add-hook 'diary-list-entries-hook 'diary-sort-entries t)
  177. in your `.emacs' file to cause the fancy diary buffer to be displayed with
  178. diary entries from various included files, each day's entries sorted into
  179. lexicographic order. Note how the sort function is placed last,
  180. so that it can sort the entries included from other files.
  181. This hook runs after `diary-nongregorian-listing-hook'. These two hooks
  182. differ only if you are using included diary files. In that case,
  183. `diary-nongregorian-listing-hook' runs for each file, whereas
  184. `diary-list-entries-hook' only runs once, for the main diary file.
  185. So for example, to sort the complete list of diary entries you would
  186. use the list-entries hook, whereas to process e.g. Islamic entries in
  187. the main file and all included files, you would use the nongregorian hook."
  188. :type 'hook
  189. :options '(diary-include-other-diary-files diary-sort-entries)
  190. :group 'diary)
  191. (define-obsolete-variable-alias 'mark-diary-entries-hook
  192. 'diary-mark-entries-hook "23.1")
  193. (defcustom diary-mark-entries-hook nil
  194. "List of functions called after marking diary entries in the calendar.
  195. You might wish to add `diary-mark-included-diary-files', in which case
  196. you will probably also want to add `diary-include-other-diary-files' to
  197. `diary-list-entries-hook'.
  198. This hook runs after `diary-nongregorian-marking-hook'. These two hooks
  199. differ only if you are using included diary files. In that case,
  200. `diary-nongregorian-marking-hook' runs for each file, whereas
  201. `diary-mark-entries-hook' only runs once, for the main diary file."
  202. :type 'hook
  203. :options '(diary-mark-included-diary-files)
  204. :group 'diary)
  205. (define-obsolete-variable-alias 'nongregorian-diary-listing-hook
  206. 'diary-nongregorian-listing-hook "23.1")
  207. (defcustom diary-nongregorian-listing-hook nil
  208. "List of functions called for listing diary file and included files.
  209. As the files are processed for diary entries, these functions are used
  210. to cull relevant entries. You can use any or all of
  211. `diary-bahai-list-entries', `diary-hebrew-list-entries', and
  212. `diary-islamic-list-entries'. The documentation for these functions
  213. describes the style of such diary entries.
  214. You can use this hook for other functions as well, if you want them to
  215. be run on the main diary file and any included diary files. Otherwise,
  216. use `diary-list-entries-hook', which runs only for the main diary file."
  217. :type 'hook
  218. :options '(diary-bahai-list-entries
  219. diary-hebrew-list-entries
  220. diary-islamic-list-entries)
  221. :group 'diary)
  222. (define-obsolete-variable-alias 'nongregorian-diary-marking-hook
  223. 'diary-nongregorian-marking-hook "23.1")
  224. (defcustom diary-nongregorian-marking-hook nil
  225. "List of functions called for marking diary file and included files.
  226. As the files are processed for diary entries, these functions are used
  227. to cull relevant entries. You can use any or all of
  228. `diary-bahai-mark-entries', `diary-hebrew-mark-entries' and
  229. `diary-islamic-mark-entries'. The documentation for these functions
  230. describes the style of such diary entries.
  231. You can use this hook for other functions as well, if you want them to
  232. be run on the main diary file and any included diary files. Otherwise,
  233. use `diary-mark-entries-hook', which runs only for the main diary file."
  234. :type 'hook
  235. :options '(diary-bahai-mark-entries
  236. diary-hebrew-mark-entries
  237. diary-islamic-mark-entries)
  238. :group 'diary)
  239. (define-obsolete-variable-alias 'print-diary-entries-hook
  240. 'diary-print-entries-hook "23.1")
  241. (defcustom diary-print-entries-hook 'lpr-buffer
  242. "Run by `diary-print-entries' after preparing a temporary diary buffer.
  243. The buffer shows only the diary entries currently visible in the
  244. diary buffer. The default just does the printing. Other uses
  245. might include, for example, rearranging the lines into order by
  246. day and time, saving the buffer instead of deleting it, or
  247. changing the function used to do the printing."
  248. :type 'hook
  249. :group 'diary)
  250. (defcustom diary-unknown-time -9999
  251. "Value returned by `diary-entry-time' when no time is found.
  252. The default value -9999 causes entries with no recognizable time
  253. to be placed before those with times; 9999 would place entries
  254. with no recognizable time after those with times."
  255. :type 'integer
  256. :group 'diary
  257. :version "20.3")
  258. (defcustom diary-mail-addr
  259. (or (bound-and-true-p user-mail-address) "")
  260. "Email address that `diary-mail-entries' will send email to."
  261. :group 'diary
  262. :type 'string
  263. :version "20.3")
  264. (defcustom diary-mail-days 7
  265. "Default number of days for `diary-mail-entries' to check."
  266. :group 'diary
  267. :type 'integer
  268. :version "20.3")
  269. (defcustom diary-remind-message
  270. '("Reminder: Only "
  271. (if (zerop (% days 7))
  272. (format "%d week%s" (/ days 7) (if (= 7 days) "" "s"))
  273. (format "%d day%s" days (if (= 1 days) "" "s")))
  274. " until "
  275. diary-entry)
  276. "Pseudo-pattern giving form of reminder messages in the fancy diary display.
  277. Used by the function `diary-remind', a pseudo-pattern is a list of
  278. expressions that can involve the keywords `days' (a number), `date'
  279. \(a list of month, day, year), and `diary-entry' (a string)."
  280. :type 'sexp
  281. :group 'diary)
  282. (define-obsolete-variable-alias 'abbreviated-calendar-year
  283. 'diary-abbreviated-year-flag "23.1")
  284. (defcustom diary-abbreviated-year-flag t
  285. "Interpret a two-digit year DD in a diary entry as either 19DD or 20DD.
  286. This applies to the Gregorian, Hebrew, Islamic, and Bahá'í calendars.
  287. When the current century is added to a two-digit year, if the result
  288. is more than 50 years in the future, the previous century is assumed.
  289. If the result is more than 50 years in the past, the next century is assumed.
  290. If this variable is nil, years must be written in full."
  291. :type 'boolean
  292. :group 'diary)
  293. (defun diary-outlook-format-1 (body)
  294. "Return a replace-match template for an element of `diary-outlook-formats'.
  295. Returns a string using match elements 1-5, where:
  296. 1 = month name, 2 = day, 3 = year, 4 = time, 5 = location; also uses
  297. %s = message subject. BODY is the string from which the matches derive."
  298. (let* ((monthname (match-string 1 body))
  299. (day (match-string 2 body))
  300. (year (match-string 3 body))
  301. ;; Blech.
  302. (month (catch 'found
  303. (dotimes (i (length calendar-month-name-array))
  304. (if (string-equal (aref calendar-month-name-array i)
  305. monthname)
  306. (throw 'found (1+ i))))
  307. nil)))
  308. ;; If we could convert the monthname to a numeric month, we can
  309. ;; use the standard function calendar-date-string.
  310. (concat (if month
  311. (calendar-date-string (list month (string-to-number day)
  312. (string-to-number year)))
  313. (cond ((eq calendar-date-style 'iso) "\\3 \\1 \\2") ; YMD
  314. ((eq calendar-date-style 'european) "\\2 \\1 \\3") ; DMY
  315. (t "\\1 \\2 \\3"))) ; MDY
  316. "\n \\4 %s, \\5")))
  317. ;; TODO Sometimes the time is in a different time-zone to the one you
  318. ;; are in. Eg in PST, you might still get an email referring to:
  319. ;; "7:00 PM-8:00 PM. Greenwich Standard Time".
  320. ;; Note that it doesn't use a standard abbreviation for the timezone,
  321. ;; or anything helpful like that.
  322. ;; Sigh, this could cause the meeting to even be on a different day
  323. ;; to that given in the When: string.
  324. ;; These things seem to come in a multipart mail with a calendar part,
  325. ;; it's probably better to use that rather than this whole thing.
  326. ;; So this is unlikely to get improved.
  327. ;; TODO Is the format of these messages actually documented anywhere?
  328. (defcustom diary-outlook-formats
  329. '(;; When: Tuesday, November 9, 2010 7:00 PM-8:00 PM. Greenwich Standard Time
  330. ;; Where: Meeting room B
  331. ("[ \t\n]*When: [[:alpha:]]+, \\([[:alpha:]]+\\) \\([0-9][0-9]*\\), \
  332. \\([0-9]\\{4\\}\\),? \\(.+\\)\n\
  333. \\(?:Where: \\(.+\n\\)\\)?" . diary-outlook-format-1))
  334. "Alist of regexps matching message text and replacement text.
  335. The regexp must match the start of the message text containing an
  336. appointment, but need not include a leading `^'. If it matches the
  337. current message, a diary entry is made from the corresponding
  338. template. If the template is a string, it should be suitable for
  339. passing to `replace-match', and so will have occurrences of `\\D' to
  340. substitute the match for the Dth subexpression. It must also contain
  341. a single `%s' which will be replaced with the text of the message's
  342. Subject field. Any other `%' characters must be doubled, so that the
  343. template can be passed to `format'.
  344. If the template is actually a function, it is called with the message
  345. body text as argument, and may use `match-string' etc. to make a
  346. template following the rules above."
  347. :type '(alist :key-type (regexp :tag "Regexp matching time/place")
  348. :value-type (choice
  349. (string :tag "Template for entry")
  350. (function :tag
  351. "Unary function providing template")))
  352. :version "22.1"
  353. :group 'diary)
  354. (defvar diary-header-line-flag)
  355. (defvar diary-header-line-format)
  356. (defun diary-set-header (symbol value)
  357. "Set SYMBOL's value to VALUE, and redraw the diary header if necessary."
  358. (let ((oldvalue (symbol-value symbol))
  359. (dbuff (and diary-file (find-buffer-visiting diary-file))))
  360. (custom-set-default symbol value)
  361. (and dbuff
  362. (not (equal value oldvalue))
  363. (with-current-buffer dbuff
  364. (if (eq major-mode 'diary-mode)
  365. (setq header-line-format (and diary-header-line-flag
  366. diary-header-line-format)))))))
  367. ;; This can be removed once the kill/yank treatment of invisible text
  368. ;; (see etc/TODO) is fixed. -- gm
  369. (defcustom diary-header-line-flag t
  370. "Non-nil means `diary-simple-display' will show a header line.
  371. The format of the header is specified by `diary-header-line-format'."
  372. :group 'diary
  373. :type 'boolean
  374. :initialize 'custom-initialize-default
  375. :set 'diary-set-header
  376. :version "22.1")
  377. (defvar diary-selective-display nil
  378. "Internal diary variable; non-nil if some diary text is hidden.")
  379. (defcustom diary-header-line-format
  380. '(:eval (calendar-string-spread
  381. (list (if diary-selective-display
  382. "Some text is hidden - press \"s\" in calendar \
  383. before edit/copy"
  384. "Diary"))
  385. ?\s (window-width)))
  386. "Format of the header line displayed by `diary-simple-display'.
  387. Only used if `diary-header-line-flag' is non-nil."
  388. :group 'diary
  389. :type 'sexp
  390. :initialize 'custom-initialize-default
  391. :set 'diary-set-header
  392. :version "23.3") ; frame-width -> window-width
  393. ;; The first version of this also checked for diary-selective-display
  394. ;; in the non-fancy case. This was an attempt to distinguish between
  395. ;; displaying the diary and just visiting the diary file. However,
  396. ;; when using fancy diary, calling diary when there are no entries to
  397. ;; display does not create the fancy buffer, nor does it set
  398. ;; diary-selective-display in the diary buffer. This means some
  399. ;; customizations will not take effect, eg:
  400. ;; http://lists.gnu.org/archive/html/emacs-pretest-bug/2007-03/msg00466.html
  401. ;; So the check for diary-selective-display was dropped. This means the
  402. ;; diary will be displayed if one customizes a diary variable while
  403. ;; just visiting the diary-file. This is i) unlikely, and ii) no great loss.
  404. ;;;###cal-autoload
  405. (defun diary-live-p ()
  406. "Return non-nil if the diary is being displayed."
  407. (or (get-buffer diary-fancy-buffer)
  408. (and diary-file (find-buffer-visiting diary-file))))
  409. ;;;###cal-autoload
  410. (defun diary-set-maybe-redraw (symbol value)
  411. "Set SYMBOL's value to VALUE, and redraw the diary if necessary.
  412. Redraws the diary if it is being displayed (note this is not the same as
  413. just visiting the `diary-file'), and SYMBOL's value is to be changed."
  414. (let ((oldvalue (symbol-value symbol)))
  415. (custom-set-default symbol value)
  416. (and (not (equal value oldvalue))
  417. (diary-live-p)
  418. ;; Note this assumes diary was called without prefix arg.
  419. (diary))))
  420. (define-obsolete-variable-alias 'number-of-diary-entries
  421. 'diary-number-of-entries "23.1")
  422. (defcustom diary-number-of-entries 1
  423. "Specifies how many days of diary entries are to be displayed initially.
  424. This variable affects the diary display when the command \\[diary] is
  425. used, or if the value of the variable `calendar-view-diary-initially-flag'
  426. is non-nil. For example, if the default value 1 is used, then only the
  427. current day's diary entries will be displayed. If the value 2 is used,
  428. then both the current day's and the next day's entries will be displayed.
  429. The value can also be a vector such as [0 2 2 2 2 4 1]; this value says
  430. to display no diary entries on Sunday, the entries for the current date
  431. and the day after on Monday through Thursday, Friday through Monday's
  432. entries on Friday, and only Saturday's entries on Saturday.
  433. This variable does not affect the diary display with the `d' command
  434. from the calendar; in that case, the prefix argument controls the number
  435. of days of diary entries displayed."
  436. :type '(choice (integer :tag "Entries")
  437. (vector :value [0 0 0 0 0 0 0]
  438. (integer :tag "Sunday")
  439. (integer :tag "Monday")
  440. (integer :tag "Tuesday")
  441. (integer :tag "Wednesday")
  442. (integer :tag "Thursday")
  443. (integer :tag "Friday")
  444. (integer :tag "Saturday")))
  445. :initialize 'custom-initialize-default
  446. :set 'diary-set-maybe-redraw
  447. :group 'diary)
  448. ;;; More user options in calendar.el, holidays.el.
  449. (defun diary-check-diary-file ()
  450. "Check that the file specified by `diary-file' exists and is readable.
  451. If so, return the expanded file name, otherwise signal an error."
  452. (if (and diary-file (file-exists-p diary-file))
  453. (if (file-readable-p diary-file)
  454. diary-file
  455. (error "Diary file `%s' is not readable" diary-file))
  456. (error "Diary file `%s' does not exist" diary-file)))
  457. ;;;###autoload
  458. (defun diary (&optional arg)
  459. "Generate the diary window for ARG days starting with the current date.
  460. If no argument is provided, the number of days of diary entries is governed
  461. by the variable `diary-number-of-entries'. A value of ARG less than 1
  462. does nothing. This function is suitable for execution in a `.emacs' file."
  463. (interactive "P")
  464. (diary-check-diary-file)
  465. (diary-list-entries (calendar-current-date)
  466. (if arg (prefix-numeric-value arg))))
  467. ;;;###cal-autoload
  468. (defun diary-view-entries (&optional arg)
  469. "Prepare and display a buffer with diary entries.
  470. Searches the file named in `diary-file' for entries that match
  471. ARG days starting with the date indicated by the cursor position
  472. in the displayed three-month calendar."
  473. (interactive "p")
  474. (diary-check-diary-file)
  475. (diary-list-entries (calendar-cursor-to-date t) arg))
  476. ;;;###cal-autoload
  477. (defun diary-view-other-diary-entries (arg dfile)
  478. "Prepare and display buffer of diary entries from an alternative diary file.
  479. Searches for entries that match ARG days, starting with the date indicated
  480. by the cursor position in the displayed three-month calendar.
  481. DFILE specifies the file to use as the diary file."
  482. (interactive
  483. (list (prefix-numeric-value current-prefix-arg)
  484. (read-file-name "Enter diary file name: " default-directory nil t)))
  485. (let ((diary-file dfile))
  486. (diary-view-entries arg)))
  487. ;;;###cal-autoload
  488. (define-obsolete-function-alias 'view-other-diary-entries
  489. 'diary-view-other-diary-entries "23.1")
  490. (defvar diary-syntax-table
  491. (let ((st (copy-syntax-table (standard-syntax-table))))
  492. (modify-syntax-entry ?* "w" st)
  493. (modify-syntax-entry ?: "w" st)
  494. st)
  495. "The syntax table used when parsing dates in the diary file.
  496. It is the standard syntax table used in Fundamental mode, but with the
  497. syntax of `*' and `:' changed to be word constituents.")
  498. (defun diary-attrtype-convert (attrvalue type)
  499. "Convert string ATTRVALUE to TYPE appropriate for a face description.
  500. Valid TYPEs are: string, symbol, int, stringtnil, tnil."
  501. (cond ((eq type 'string) attrvalue)
  502. ((eq type 'symbol) (intern-soft attrvalue))
  503. ((eq type 'int) (string-to-number attrvalue))
  504. ((eq type 'stringtnil)
  505. (cond ((string-equal "t" attrvalue) t)
  506. ((string-equal "nil" attrvalue) nil)
  507. (t attrvalue)))
  508. ((eq type 'tnil) (string-equal "t" attrvalue))))
  509. (defun diary-pull-attrs (entry fileglobattrs)
  510. "Search for matches for regexps from `diary-face-attrs'.
  511. If ENTRY is nil, searches from the start of the current buffer, and
  512. prepends all regexps with `diary-glob-file-regexp-prefix'.
  513. If ENTRY is a string, search for matches in that string, and remove them.
  514. Returns a list of ENTRY followed by (ATTRIBUTE VALUE) pairs.
  515. When ENTRY is non-nil, FILEGLOBATTRS forms the start of the (ATTRIBUTE VALUE)
  516. pairs."
  517. (let (regexp regnum attrname attrname attrvalue type ret-attr)
  518. (if (null entry)
  519. (save-excursion
  520. (dolist (attr diary-face-attrs)
  521. ;; FIXME inefficient searching.
  522. (goto-char (point-min))
  523. (setq regexp (concat diary-glob-file-regexp-prefix (car attr))
  524. regnum (cadr attr)
  525. attrname (nth 2 attr)
  526. type (nth 3 attr)
  527. attrvalue (if (re-search-forward regexp nil t)
  528. (match-string-no-properties regnum)))
  529. (and attrvalue
  530. (setq attrvalue (diary-attrtype-convert attrvalue type))
  531. (setq ret-attr (append ret-attr
  532. (list attrname attrvalue))))))
  533. (setq ret-attr fileglobattrs)
  534. (dolist (attr diary-face-attrs)
  535. (setq regexp (car attr)
  536. regnum (cadr attr)
  537. attrname (nth 2 attr)
  538. type (nth 3 attr)
  539. attrvalue nil)
  540. ;; If multiple matches, replace all, use the last (which may
  541. ;; be the first instance in the line, if the regexp is
  542. ;; anchored with $).
  543. (while (string-match regexp entry)
  544. (setq attrvalue (match-string-no-properties regnum entry)
  545. entry (replace-match "" t t entry)))
  546. (and attrvalue
  547. (setq attrvalue (diary-attrtype-convert attrvalue type))
  548. (setq ret-attr (append ret-attr (list attrname attrvalue))))))
  549. (list entry ret-attr)))
  550. (defvar diary-modify-entry-list-string-function nil
  551. "Function applied to entry string before putting it into the entries list.
  552. Can be used by programs integrating a diary list into other buffers (e.g.
  553. org.el and planner.el) to modify the string or add properties to it.
  554. The function takes a string argument and must return a string.")
  555. (defvar diary-entries-list) ; bound in diary-list-entries
  556. (defun diary-add-to-list (date string specifier &optional marker
  557. globcolor literal)
  558. "Add an entry to `diary-entries-list'.
  559. Do nothing if DATE or STRING are nil. DATE is the (MONTH DAY
  560. YEAR) for which the entry applies; STRING is the text of the
  561. entry as it will appear in the diary (i.e. with any format
  562. strings such as \"%d\" expanded); SPECIFIER is the date part of
  563. the entry as it appears in the diary-file; LITERAL is the entry
  564. as it appears in the diary-file (i.e. before expansion).
  565. If LITERAL is nil, it is taken to be the same as STRING.
  566. The entry is added to the list as (DATE STRING SPECIFIER LOCATOR
  567. GLOBCOLOR), where LOCATOR has the form (MARKER FILENAME LITERAL),
  568. FILENAME being the file containing the diary entry.
  569. Modifies STRING using `diary-modify-entry-list-string-function', if non-nil.
  570. Also removes the region between `diary-comment-start' and
  571. `diary-comment-end', if the former is non-nil."
  572. (when (and date string)
  573. ;; b-f-n is nil if we are visiting an include file in a temp-buffer.
  574. (let ((dfile (or (buffer-file-name) diary-file))
  575. cstart)
  576. (if diary-file-name-prefix
  577. (let ((prefix (funcall diary-file-name-prefix-function dfile)))
  578. (or (string-equal prefix "")
  579. (setq string (format "[%s] %s" prefix string)))))
  580. (and diary-modify-entry-list-string-function
  581. (setq string (funcall diary-modify-entry-list-string-function
  582. string)))
  583. (when (and diary-comment-start
  584. (string-match (setq cstart (regexp-quote diary-comment-start))
  585. string))
  586. ;; Preserve the value with the comments.
  587. (or literal (setq literal string))
  588. ;; Handles multiple comments per entry, so long as each is on
  589. ;; a single line, and each line has no more than one comment.
  590. (setq string (replace-regexp-in-string
  591. (format "%s.*%s" cstart (regexp-quote diary-comment-end))
  592. "" string)))
  593. (setq diary-entries-list
  594. (append diary-entries-list
  595. (list (list date string specifier
  596. (list marker dfile literal)
  597. globcolor)))))))
  598. (define-obsolete-function-alias 'add-to-diary-list 'diary-add-to-list "23.1")
  599. (defun diary-list-entries-2 (date mark globattr list-only
  600. &optional months symbol gdate)
  601. "Internal subroutine of `diary-list-entries'.
  602. Find diary entries applying to DATE, by searching from point-min for
  603. each element of `diary-date-forms'. MARK indicates an entry is non-marking.
  604. GLOBATTR is the list of global file attributes. If LIST-ONLY is
  605. non-nil, don't change the buffer, only return a list of entries.
  606. Optional array MONTHS replaces `calendar-month-name-array', and
  607. means months cannot be abbreviated. Optional string SYMBOL marks diary
  608. entries of the desired type. If DATE is not Gregorian, then the
  609. Gregorian equivalent should be provided via GDATE. Returns non-nil if
  610. any entries were found."
  611. (let* ((month (calendar-extract-month date))
  612. (day (calendar-extract-day date))
  613. (year (calendar-extract-year date))
  614. (dayname (format "%s\\|%s\\.?" (calendar-day-name date)
  615. (calendar-day-name date 'abbrev)))
  616. (calendar-month-name-array (or months calendar-month-name-array))
  617. (monthname (format "\\*\\|%s%s" (calendar-month-name month)
  618. (if months ""
  619. (format "\\|%s\\.?"
  620. (calendar-month-name month 'abbrev)))))
  621. (month (format "\\*\\|0*%d" month))
  622. (day (format "\\*\\|0*%d" day))
  623. (year (format "\\*\\|0*%d%s" year
  624. (if diary-abbreviated-year-flag
  625. (format "\\|%02d" (% year 100))
  626. "")))
  627. (case-fold-search t)
  628. entry-found)
  629. (dolist (date-form diary-date-forms)
  630. (let ((backup (when (eq (car date-form) 'backup)
  631. (setq date-form (cdr date-form))
  632. t))
  633. ;; date-form uses day etc as set above.
  634. (regexp (format "^%s?%s\\(%s\\)" (regexp-quote mark)
  635. (if symbol (regexp-quote symbol) "")
  636. (mapconcat 'eval date-form "\\)\\(?:")))
  637. entry-start date-start temp)
  638. (goto-char (point-min))
  639. (while (re-search-forward regexp nil t)
  640. (if backup (re-search-backward "\\<" nil t))
  641. ;; regexp moves us past the end of date, onto the next line.
  642. ;; Trailing whitespace after date not allowed (see diary-file).
  643. (if (and (bolp) (not (looking-at "[ \t]")))
  644. ;; Diary entry that consists only of date.
  645. (backward-char 1)
  646. ;; Found a nonempty diary entry--make it
  647. ;; visible and add it to the list.
  648. (setq date-start (line-end-position 0))
  649. ;; Actual entry starts on the next-line?
  650. (if (looking-at "[ \t]*\n[ \t]") (forward-line 1))
  651. (setq entry-found t
  652. entry-start (point))
  653. (forward-line 1)
  654. (while (looking-at "[ \t]") ; continued entry
  655. (forward-line 1))
  656. (unless (and (eobp) (not (bolp)))
  657. (backward-char 1))
  658. (unless list-only
  659. (remove-overlays date-start (point) 'invisible 'diary))
  660. (setq temp (diary-pull-attrs
  661. (buffer-substring-no-properties
  662. entry-start (point)) globattr))
  663. (diary-add-to-list
  664. (or gdate date) (car temp)
  665. (buffer-substring-no-properties (1+ date-start) (1- entry-start))
  666. (copy-marker entry-start) (cadr temp))))))
  667. entry-found))
  668. (defvar original-date) ; from diary-list-entries
  669. (defvar file-glob-attrs)
  670. (defvar list-only)
  671. (defvar number)
  672. (defun diary-list-entries-1 (months symbol absfunc)
  673. "List diary entries of a certain type.
  674. MONTHS is an array of month names. SYMBOL marks diary entries of the type
  675. in question. ABSFUNC is a function that converts absolute dates to dates
  676. of the appropriate type."
  677. (let ((gdate original-date))
  678. (dotimes (_idummy number)
  679. (diary-list-entries-2
  680. (funcall absfunc (calendar-absolute-from-gregorian gdate))
  681. diary-nonmarking-symbol file-glob-attrs list-only months symbol gdate)
  682. (setq gdate
  683. (calendar-gregorian-from-absolute
  684. (1+ (calendar-absolute-from-gregorian gdate))))))
  685. (goto-char (point-min)))
  686. (defvar diary-included-files nil
  687. "List of any diary files included in the last call to `diary-list-entries'.
  688. Or to `diary-mark-entries'.")
  689. (defun diary-list-entries (date number &optional list-only)
  690. "Create and display a buffer containing the relevant lines in `diary-file'.
  691. Selects entries for NUMBER days starting with date DATE. Hides any
  692. other entries using overlays. If NUMBER is less than 1, this function
  693. does nothing.
  694. Returns a list of all relevant diary entries found.
  695. The list entries have the form ((MONTH DAY YEAR) STRING SPECIFIER) where
  696. \(MONTH DAY YEAR) is the date of the entry, STRING is the entry text, and
  697. SPECIFIER is the applicability. If the variable `diary-list-include-blanks'
  698. is non-nil, this list includes a dummy diary entry consisting of the empty
  699. string for a date with no diary entries.
  700. If producing entries for multiple dates (i.e., NUMBER > 1), then
  701. this function normally returns the entries from any given diary
  702. file in date order. The entries for any given day are in the
  703. order in which they were found in the file, not necessarily in
  704. time-of-day order. Note that any functions present on the
  705. hooks (see below) may add entries, or change the order. For
  706. example, `diary-include-other-diary-files' adds entries from any
  707. include files that it finds to the end of the original list. The
  708. entries from each file will be in date order, but the overall
  709. list will not be. If you want the entire list to be in time
  710. order, add `diary-sort-entries' to the end of `diary-list-entries-hook'.
  711. After preparing the initial list, hooks run in this order:
  712. `diary-nongregorian-listing-hook' runs for the main diary file,
  713. and each included file. For example, this is the appropriate hook
  714. to process Islamic entries in all diary files.
  715. `diary-list-entries-hook' runs once only, for the main diary file.
  716. For example, this is appropriate for sorting all the entries.
  717. If not using include files, there is no difference from the previous
  718. hook.
  719. `diary-hook' runs last, after the diary is displayed.
  720. This is used e.g. by `appt-check'.
  721. Functions called by these hooks may use the variables ORIGINAL-DATE
  722. and NUMBER, which are the arguments with which this function was called.
  723. Note that hook functions should _not_ use DATE, but ORIGINAL-DATE.
  724. \(Sexp diary entries may use DATE - see `diary-list-sexp-entries'.)
  725. This function displays the list using `diary-display-function', unless
  726. LIST-ONLY is non-nil, in which case it just returns the list."
  727. (unless number
  728. (setq number (if (vectorp diary-number-of-entries)
  729. (aref diary-number-of-entries (calendar-day-of-week date))
  730. diary-number-of-entries)))
  731. (when (> number 0)
  732. (let* ((original-date date) ; save for possible use in the hooks
  733. (date-string (calendar-date-string date))
  734. (diary-buffer (find-buffer-visiting diary-file))
  735. ;; Dynamically bound in diary-include-files.
  736. (d-incp (and (boundp 'diary-including) diary-including))
  737. diary-entries-list file-glob-attrs temp-buff)
  738. (unless d-incp
  739. (setq diary-included-files nil)
  740. (message "Preparing diary..."))
  741. (unwind-protect
  742. (with-current-buffer (or diary-buffer
  743. (if list-only
  744. (setq temp-buff (generate-new-buffer
  745. " *diary-temp*"))
  746. (find-file-noselect diary-file t)))
  747. (if diary-buffer
  748. (or (verify-visited-file-modtime diary-buffer)
  749. (revert-buffer t t)))
  750. (if temp-buff
  751. ;; If including, caller has already verified it is readable.
  752. (insert-file-contents diary-file)
  753. ;; Setup things like the header-line-format and invisibility-spec.
  754. (if (eq major-mode (default-value 'major-mode))
  755. (diary-mode)
  756. ;; This kludge is to make customizations to
  757. ;; diary-header-line-flag after diary has been displayed
  758. ;; take effect. Unconditionally calling (diary-mode)
  759. ;; clobbers file local variables.
  760. ;; http://lists.gnu.org/archive/html/emacs-pretest-bug/2007-03/msg00363.html
  761. ;; http://lists.gnu.org/archive/html/emacs-pretest-bug/2007-04/msg00404.html
  762. (if (eq major-mode 'diary-mode)
  763. (setq header-line-format (and diary-header-line-flag
  764. diary-header-line-format)))))
  765. ;; d-s-p is passed to the diary display function.
  766. (let ((diary-saved-point (point)))
  767. (save-excursion
  768. (save-restriction
  769. (widen) ; bug#5093
  770. (setq file-glob-attrs (cadr (diary-pull-attrs nil "")))
  771. (with-syntax-table diary-syntax-table
  772. (goto-char (point-min))
  773. (unless list-only
  774. (let ((ol (make-overlay (point-min) (point-max) nil t nil)))
  775. (set (make-local-variable 'diary-selective-display) t)
  776. (overlay-put ol 'invisible 'diary)
  777. (overlay-put ol 'evaporate t)))
  778. (dotimes (_idummy number)
  779. (let ((sexp-found (diary-list-sexp-entries date))
  780. (entry-found (diary-list-entries-2
  781. date diary-nonmarking-symbol
  782. file-glob-attrs list-only)))
  783. (if diary-list-include-blanks
  784. (or sexp-found entry-found
  785. (diary-add-to-list date "" "" "" "")))
  786. (setq date
  787. (calendar-gregorian-from-absolute
  788. (1+ (calendar-absolute-from-gregorian date)))))))
  789. (goto-char (point-min))
  790. ;; Although it looks like list-entries-hook runs
  791. ;; every time, diary-include-other-diary-files
  792. ;; binds it to nil (essentially) when it runs
  793. ;; in included files.
  794. (run-hooks 'diary-nongregorian-listing-hook
  795. 'diary-list-entries-hook)
  796. ;; We could make this explicit:
  797. ;;; (run-hooks 'diary-nongregorian-listing-hook)
  798. ;;; (if d-incp
  799. ;;; (diary-include-other-diary-files) ; recurse
  800. ;;; (run-hooks 'diary-list-entries-hook))
  801. (unless list-only
  802. (if (and diary-display-function
  803. (listp diary-display-function))
  804. ;; Backwards compatibility.
  805. (run-hooks 'diary-display-function)
  806. (funcall (or diary-display-function
  807. 'diary-simple-display))))
  808. (run-hooks 'diary-hook)))))
  809. (and temp-buff (buffer-name temp-buff) (kill-buffer temp-buff)))
  810. (or d-incp (message "Preparing diary...done"))
  811. diary-entries-list)))
  812. (defun diary-unhide-everything ()
  813. "Show all invisible text in the diary."
  814. (kill-local-variable 'diary-selective-display)
  815. (save-restriction ; bug#5477
  816. (widen)
  817. (remove-overlays (point-min) (point-max) 'invisible 'diary))
  818. (kill-local-variable 'mode-line-format))
  819. (defvar original-date) ; bound in diary-list-entries
  820. ;(defvar number) ; already declared above
  821. (defun diary-include-files (&optional mark)
  822. "Process diary entries from included diary files.
  823. By default, lists included entries, but if optional argument MARK is non-nil
  824. marks entries instead.
  825. For example, this enables you to share common diary files.
  826. Specify include files using lines matching `diary-include-string', e.g.
  827. #include \"filename\"
  828. This is recursive; that is, included files may include other files."
  829. (goto-char (point-min))
  830. (while (re-search-forward
  831. (format "^%s \"\\([^\"]*\\)\"" (regexp-quote diary-include-string))
  832. nil t)
  833. (let ((diary-file (match-string-no-properties 1))
  834. (diary-mark-entries-hook 'diary-mark-included-diary-files)
  835. (diary-list-entries-hook 'diary-include-other-diary-files)
  836. (diary-including t)
  837. diary-hook diary-list-include-blanks efile)
  838. (if (file-exists-p diary-file)
  839. (if (file-readable-p diary-file)
  840. (if (member (setq efile (expand-file-name diary-file))
  841. diary-included-files)
  842. (error "Recursive diary include for %s" diary-file)
  843. (setq diary-included-files
  844. (append diary-included-files (list efile)))
  845. (if mark
  846. (diary-mark-entries)
  847. (setq diary-entries-list
  848. (append diary-entries-list
  849. (diary-list-entries original-date number t)))))
  850. (beep)
  851. (message "Can't read included diary file %s" diary-file)
  852. (sleep-for 2))
  853. (beep)
  854. (message "Can't find included diary file %s" diary-file)
  855. (sleep-for 2))))
  856. (goto-char (point-min)))
  857. (defun diary-include-other-diary-files ()
  858. "Add diary entries from included diary files to `diary-entries-list'.
  859. To use, add this function to `diary-list-entries-hook'.
  860. For details, see `diary-include-files'.
  861. See also `diary-mark-included-diary-files'."
  862. (diary-include-files))
  863. (define-obsolete-function-alias 'include-other-diary-files
  864. 'diary-include-other-diary-files "23.1")
  865. (defvar date-string) ; bound in diary-list-entries
  866. (defun diary-display-no-entries ()
  867. "Common subroutine of `diary-simple-display' and `diary-fancy-display'.
  868. Handles the case where there are no diary entries.
  869. Returns a cons (NOENTRIES . HOLIDAY-STRING)."
  870. (let* ((holiday-list (if diary-show-holidays-flag
  871. (calendar-check-holidays original-date)))
  872. (hol-string (format "%s%s%s"
  873. date-string
  874. (if holiday-list ": " "")
  875. (mapconcat 'identity holiday-list "; ")))
  876. (msg (format "No diary entries for %s" hol-string))
  877. ;; Empty list, or single item with no text.
  878. ;; FIXME multiple items with no text?
  879. (noentries (or (not diary-entries-list)
  880. (and (not (cdr diary-entries-list))
  881. (string-equal "" (cadr
  882. (car diary-entries-list)))))))
  883. ;; Inconsistency: whether or not the holidays are displayed in a
  884. ;; separate buffer depends on if there are diary entries.
  885. (when noentries
  886. (if (or (< (length msg) (frame-width))
  887. (not holiday-list))
  888. (message "%s" msg)
  889. ;; holiday-list which is too wide for a message gets a buffer.
  890. (calendar-in-read-only-buffer holiday-buffer
  891. (calendar-set-mode-line (format "Holidays for %s" date-string))
  892. (insert (mapconcat 'identity holiday-list "\n")))
  893. (message "No diary entries for %s" date-string)))
  894. (cons noentries hol-string)))
  895. (defvar diary-saved-point) ; bound in diary-list-entries
  896. (defun diary-simple-display ()
  897. "Display the diary buffer if there are any relevant entries or holidays.
  898. Entries that do not apply are made invisible. Holidays are shown
  899. in the mode line. This is an option for `diary-display-function'."
  900. ;; If selected window is dedicated (to the calendar), need a new one
  901. ;; to display the diary.
  902. (let* ((pop-up-frames (or pop-up-frames
  903. (window-dedicated-p (selected-window))))
  904. (dbuff (find-buffer-visiting diary-file))
  905. (empty (diary-display-no-entries)))
  906. ;; This may be too wide, but when simple diary is used there is
  907. ;; nowhere else for the holidays to go. Also, it is documented in
  908. ;; diary-show-holidays-flag that the holidays go in the mode-line.
  909. ;; FIXME however if there are no diary entries a separate buffer
  910. ;; is displayed - this is inconsistent.
  911. (with-current-buffer dbuff
  912. (calendar-set-mode-line (format "Diary for %s" (cdr empty))))
  913. (unless (car empty) ; no entries
  914. (with-current-buffer dbuff
  915. (let ((window (display-buffer (current-buffer))))
  916. ;; d-s-p is passed from diary-list-entries.
  917. (set-window-point window diary-saved-point)
  918. (set-window-start window (point-min)))))))
  919. (define-obsolete-function-alias 'simple-diary-display
  920. 'diary-simple-display "23.1")
  921. (define-button-type 'diary-entry 'action #'diary-goto-entry
  922. 'face 'diary-button 'help-echo "Find this diary entry"
  923. 'follow-link t)
  924. (defun diary-goto-entry (button)
  925. "Jump to the diary entry for the BUTTON at point."
  926. (let* ((locator (button-get button 'locator))
  927. (marker (car locator))
  928. markbuf file)
  929. ;; If marker pointing to diary location is valid, use that.
  930. (if (and marker (setq markbuf (marker-buffer marker)))
  931. (progn
  932. (pop-to-buffer markbuf)
  933. (goto-char (marker-position marker)))
  934. ;; Marker is invalid (eg buffer has been killed).
  935. (or (and (setq file (cadr locator))
  936. (file-exists-p file)
  937. (find-file-other-window file)
  938. (progn
  939. (when (eq major-mode (default-value 'major-mode)) (diary-mode))
  940. (goto-char (point-min))
  941. (if (re-search-forward (format "%s.*\\(%s\\)"
  942. (regexp-quote (nth 2 locator))
  943. (regexp-quote (nth 3 locator)))
  944. nil t)
  945. (goto-char (match-beginning 1)))))
  946. (message "Unable to locate this diary entry")))))
  947. (defun diary-fancy-display ()
  948. "Prepare a diary buffer with relevant entries in a fancy, noneditable form.
  949. Holidays are shown unless `diary-show-holidays-flag' is nil.
  950. Days with no diary entries are not shown (even if that day is a
  951. holiday), unless `diary-list-include-blanks' is non-nil.
  952. This is an option for `diary-display-function'."
  953. ;; Turn off selective-display in the diary file's buffer.
  954. (with-current-buffer (find-buffer-visiting diary-file)
  955. (diary-unhide-everything))
  956. (unless (car (diary-display-no-entries)) ; no entries
  957. ;; Prepare the fancy diary buffer.
  958. (calendar-in-read-only-buffer diary-fancy-buffer
  959. (calendar-set-mode-line "Diary Entries")
  960. (let ((holiday-list-last-month 1)
  961. (holiday-list-last-year 1)
  962. (date (list 0 0 0))
  963. holiday-list)
  964. (dolist (entry diary-entries-list)
  965. (unless (calendar-date-equal date (car entry))
  966. (setq date (car entry))
  967. (and diary-show-holidays-flag
  968. (calendar-date-compare
  969. (list (list holiday-list-last-month
  970. (calendar-last-day-of-month
  971. holiday-list-last-month
  972. holiday-list-last-year)
  973. holiday-list-last-year))
  974. (list date))
  975. ;; We need to get the holidays for the next 3 months.
  976. (setq holiday-list-last-month
  977. (calendar-extract-month date)
  978. holiday-list-last-year
  979. (calendar-extract-year date))
  980. (progn
  981. (calendar-increment-month
  982. holiday-list-last-month holiday-list-last-year 1)
  983. t)
  984. (setq holiday-list
  985. (let ((displayed-month holiday-list-last-month)
  986. (displayed-year holiday-list-last-year))
  987. (calendar-holiday-list)))
  988. (calendar-increment-month
  989. holiday-list-last-month holiday-list-last-year 1))
  990. (let ((longest 0)
  991. date-holiday-list cc)
  992. ;; Make a list of all holidays for date.
  993. (dolist (h holiday-list)
  994. (if (calendar-date-equal date (car h))
  995. (setq date-holiday-list (append date-holiday-list
  996. (cdr h)))))
  997. (insert (if (bobp) "" ?\n) (calendar-date-string date))
  998. (if date-holiday-list (insert ": "))
  999. (setq cc (current-column))
  1000. (insert (mapconcat (lambda (x)
  1001. (setq longest (max longest (length x)))
  1002. x)
  1003. date-holiday-list
  1004. (concat "\n" (make-string cc ?\s))))
  1005. (insert ?\n (make-string (+ cc longest) ?=) ?\n)))
  1006. (let ((this-entry (cadr entry))
  1007. this-loc marks temp-face)
  1008. (unless (zerop (length this-entry))
  1009. (if (setq this-loc (nth 3 entry))
  1010. (insert-button this-entry
  1011. ;; (MARKER FILENAME SPECIFIER LITERAL)
  1012. 'locator (list (car this-loc)
  1013. (cadr this-loc)
  1014. (nth 2 entry)
  1015. (or (nth 2 this-loc)
  1016. (nth 1 entry)))
  1017. :type 'diary-entry)
  1018. (insert this-entry))
  1019. (insert ?\n)
  1020. ;; Doesn't make sense to check font-lock-mode - see
  1021. ;; comments above diary-entry-marker in calendar.el.
  1022. (and ; font-lock-mode
  1023. (setq marks (nth 4 entry))
  1024. (save-excursion
  1025. (setq temp-face (calendar-make-temp-face marks))
  1026. (search-backward this-entry)
  1027. (overlay-put
  1028. (make-overlay (match-beginning 0) (match-end 0))
  1029. 'face temp-face)))))))
  1030. ;; FIXME can't remember what this check was for.
  1031. ;; To prevent something looping, or a minor optimization?
  1032. (if (eq major-mode 'diary-fancy-display-mode)
  1033. (run-hooks 'diary-fancy-display-mode-hook)
  1034. (diary-fancy-display-mode))
  1035. (calendar-set-mode-line date-string))))
  1036. (define-obsolete-function-alias 'fancy-diary-display
  1037. 'diary-fancy-display "23.1")
  1038. ;; FIXME modernize?
  1039. (defun diary-print-entries ()
  1040. "Print a hard copy of the diary display.
  1041. If the simple diary display is being used, prepare a temp buffer with the
  1042. visible lines of the diary buffer, add a heading line composed from the mode
  1043. line, print the temp buffer, and destroy it.
  1044. If the fancy diary display is being used, just print the buffer.
  1045. The hooks given by the variable `diary-print-entries-hook' are called to do
  1046. the actual printing."
  1047. (interactive)
  1048. (let ((diary-buffer (get-buffer diary-fancy-buffer))
  1049. temp-buffer heading start end)
  1050. (if diary-buffer
  1051. (with-current-buffer diary-buffer
  1052. (run-hooks 'diary-print-entries-hook))
  1053. (or (setq diary-buffer (find-buffer-visiting diary-file))
  1054. (error "You don't have a diary buffer!"))
  1055. ;; Name affects printing?
  1056. (setq temp-buffer (get-buffer-create " *Printable Diary Entries*"))
  1057. (with-current-buffer diary-buffer
  1058. (setq heading
  1059. (if (not (stringp mode-line-format))
  1060. "All Diary Entries"
  1061. (string-match "^-*\\([^-].*[^-]\\)-*$" mode-line-format)
  1062. (match-string 1 mode-line-format))
  1063. start (point-min))
  1064. (while
  1065. (progn
  1066. (setq end (next-single-char-property-change start 'invisible))
  1067. (unless (get-char-property start 'invisible)
  1068. (with-current-buffer temp-buffer
  1069. (insert-buffer-substring diary-buffer start end)))
  1070. (setq start end)
  1071. (and end (< end (point-max))))))
  1072. (set-buffer temp-buffer)
  1073. (goto-char (point-min))
  1074. (insert heading "\n"
  1075. (make-string (length heading) ?=) "\n")
  1076. (run-hooks 'diary-print-entries-hook)
  1077. (kill-buffer temp-buffer))))
  1078. (define-obsolete-function-alias 'print-diary-entries
  1079. 'diary-print-entries "23.1")
  1080. ;;;###cal-autoload
  1081. (defun diary-show-all-entries ()
  1082. "Show all of the diary entries in the diary file.
  1083. This function gets rid of the selective display of the diary file so that
  1084. all entries, not just some, are visible. If there is no diary buffer, one
  1085. is created."
  1086. (interactive)
  1087. (let* ((d-file (diary-check-diary-file))
  1088. (pop-up-frames (or pop-up-frames
  1089. (window-dedicated-p (selected-window))))
  1090. (win (selected-window))
  1091. (height (window-height)))
  1092. (with-current-buffer (or (find-buffer-visiting d-file)
  1093. (find-file-noselect d-file t))
  1094. (when (eq major-mode (default-value 'major-mode)) (diary-mode))
  1095. (diary-unhide-everything)
  1096. (display-buffer (current-buffer))
  1097. (when (and (/= height (window-height win))
  1098. (with-current-buffer (window-buffer win)
  1099. (derived-mode-p 'calendar-mode)))
  1100. (fit-window-to-buffer win)))))
  1101. ;;;###autoload
  1102. (defun diary-mail-entries (&optional ndays)
  1103. "Send a mail message showing diary entries for next NDAYS days.
  1104. If no prefix argument is given, NDAYS is set to `diary-mail-days'.
  1105. Mail is sent to the address specified by `diary-mail-addr'.
  1106. Here is an example of a script to call `diary-mail-entries',
  1107. suitable for regular scheduling using cron (or at). Note that
  1108. since `emacs -script' does not load your `.emacs' file, you
  1109. should ensure that all relevant variables are set.
  1110. #!/usr/bin/emacs -script
  1111. ;; diary-rem.el - run the Emacs diary-reminder
  1112. \(setq diary-mail-days 3
  1113. diary-file \"/path/to/diary.file\"
  1114. calendar-date-style 'european
  1115. diary-mail-addr \"user@host.name\")
  1116. \(diary-mail-entries)
  1117. # diary-rem.el ends here
  1118. "
  1119. (interactive "P")
  1120. (if (string-equal diary-mail-addr "")
  1121. (error "You must set `diary-mail-addr' to use this command")
  1122. (let ((diary-display-function 'diary-fancy-display))
  1123. (diary-list-entries (calendar-current-date) (or ndays diary-mail-days)))
  1124. (compose-mail diary-mail-addr
  1125. (concat "Diary entries generated "
  1126. (calendar-date-string (calendar-current-date))))
  1127. (insert
  1128. (if (get-buffer diary-fancy-buffer)
  1129. (with-current-buffer diary-fancy-buffer (buffer-string))
  1130. "No entries found"))
  1131. (call-interactively (get mail-user-agent 'sendfunc))))
  1132. (defun diary-name-pattern (string-array &optional abbrev-array paren)
  1133. "Return a regexp matching the strings in the array STRING-ARRAY.
  1134. If the optional argument ABBREV-ARRAY is present, the regexp
  1135. also matches the supplied abbreviations, with or without final `.'
  1136. characters. If the optional argument PAREN is non-nil, surrounds
  1137. the regexp with parentheses."
  1138. (regexp-opt (append string-array
  1139. abbrev-array
  1140. (if abbrev-array
  1141. (mapcar (lambda (e) (format "%s." e))
  1142. abbrev-array))
  1143. nil)
  1144. paren))
  1145. (defvar diary-marking-entries-flag nil
  1146. "True during the marking of diary entries, nil otherwise.")
  1147. (defvar diary-marking-entry-flag nil
  1148. "True during the marking of diary entries, if current entry is marking.")
  1149. ;; file-glob-attrs bound in diary-mark-entries.
  1150. (defun diary-mark-entries-1 (markfunc &optional months symbol absfunc)
  1151. "Mark diary entries of a certain type.
  1152. MARKFUNC is a function that marks entries of the appropriate type
  1153. matching a given date pattern. MONTHS is an array of month names.
  1154. SYMBOL marks diary entries of the type in question. ABSFUNC is a
  1155. function that converts absolute dates to dates of the appropriate type. "
  1156. (let ((dayname (diary-name-pattern calendar-day-name-array
  1157. calendar-day-abbrev-array))
  1158. (monthname (format "%s\\|\\*"
  1159. (if months
  1160. (diary-name-pattern months)
  1161. (diary-name-pattern calendar-month-name-array
  1162. calendar-month-abbrev-array))))
  1163. (month "[0-9]+\\|\\*")
  1164. (day "[0-9]+\\|\\*")
  1165. (year "[0-9]+\\|\\*")
  1166. (case-fold-search t)
  1167. marks)
  1168. (dolist (date-form diary-date-forms)
  1169. (if (eq (car date-form) 'backup) ; ignore 'backup directive
  1170. (setq date-form (cdr date-form)))
  1171. (let* ((l (length date-form))
  1172. (d-name-pos (- l (length (memq 'dayname date-form))))
  1173. (d-name-pos (if (/= l d-name-pos) (1+ d-name-pos)))
  1174. (m-name-pos (- l (length (memq 'monthname date-form))))
  1175. (m-name-pos (if (/= l m-name-pos) (1+ m-name-pos)))
  1176. (d-pos (- l (length (memq 'day date-form))))
  1177. (d-pos (if (/= l d-pos) (1+ d-pos)))
  1178. (m-pos (- l (length (memq 'month date-form))))
  1179. (m-pos (if (/= l m-pos) (1+ m-pos)))
  1180. (y-pos (- l (length (memq 'year date-form))))
  1181. (y-pos (if (/= l y-pos) (1+ y-pos)))
  1182. (regexp (format "^%s\\(%s\\)"
  1183. (if symbol (regexp-quote symbol) "")
  1184. (mapconcat 'eval date-form "\\)\\("))))
  1185. (goto-char (point-min))
  1186. (while (re-search-forward regexp nil t)
  1187. (let* ((dd-name
  1188. (if d-name-pos
  1189. (match-string-no-properties d-name-pos)))
  1190. (mm-name
  1191. (if m-name-pos
  1192. (match-string-no-properties m-name-pos)))
  1193. (mm (string-to-number
  1194. (if m-pos
  1195. (match-string-no-properties m-pos)
  1196. "")))
  1197. (dd (string-to-number
  1198. (if d-pos
  1199. (match-string-no-properties d-pos)
  1200. "")))
  1201. (y-str (if y-pos
  1202. (match-string-no-properties y-pos)))
  1203. (yy (if (not y-str)
  1204. 0
  1205. (if (and (= (length y-str) 2)
  1206. diary-abbreviated-year-flag)
  1207. (let* ((current-y
  1208. (calendar-extract-year
  1209. (if absfunc
  1210. (funcall
  1211. absfunc
  1212. (calendar-absolute-from-gregorian
  1213. (calendar-current-date)))
  1214. (calendar-current-date))))
  1215. (y (+ (string-to-number y-str)
  1216. ;; Current century, eg 2000.
  1217. (* 100 (/ current-y 100))))
  1218. (offset (- y current-y)))
  1219. ;; Add 2-digit year to current century.
  1220. ;; If more than 50 years in the future,
  1221. ;; assume last century. If more than 50
  1222. ;; years in the past, assume next century.
  1223. (if (> offset 50)
  1224. (- y 100)
  1225. (if (< offset -50)
  1226. (+ y 100)
  1227. y)))
  1228. (string-to-number y-str)))))
  1229. (setq marks (cadr (diary-pull-attrs
  1230. (buffer-substring-no-properties
  1231. (point) (line-end-position))
  1232. file-glob-attrs)))
  1233. ;; Only mark all days of a given name if the pattern
  1234. ;; contains no more specific elements.
  1235. (if (and dd-name (not (or d-pos m-pos y-pos)))
  1236. (calendar-mark-days-named
  1237. (cdr (assoc-string dd-name
  1238. (calendar-make-alist
  1239. calendar-day-name-array
  1240. 0 nil calendar-day-abbrev-array
  1241. (mapcar (lambda (e)
  1242. (format "%s." e))
  1243. calendar-day-abbrev-array))
  1244. t)) marks)
  1245. (if mm-name
  1246. (setq mm
  1247. (if (string-equal mm-name "*") 0
  1248. (cdr (assoc-string
  1249. mm-name
  1250. (if months (calendar-make-alist months)
  1251. (calendar-make-alist
  1252. calendar-month-name-array
  1253. 1 nil calendar-month-abbrev-array
  1254. (mapcar (lambda (e)
  1255. (format "%s." e))
  1256. calendar-month-abbrev-array)))
  1257. t)))))
  1258. (funcall markfunc mm dd yy marks))))))))
  1259. ;;;###cal-autoload
  1260. (defun diary-mark-entries (&optional redraw)
  1261. "Mark days in the calendar window that have diary entries.
  1262. Marks each entry in the diary that is visible in the calendar window.
  1263. After marking the entries, runs `diary-nongregorian-marking-hook'
  1264. for the main diary file, and each included file. For example,
  1265. this is the appropriate hook to process Islamic entries in all
  1266. diary files. Next `diary-mark-entries-hook' runs, for the main diary
  1267. file only. If not using include files, there is no difference between
  1268. these two hooks.
  1269. If the optional argument REDRAW is non-nil (which is the case
  1270. interactively, for example) then this first removes any existing diary
  1271. marks. This is intended to deal with deleted diary entries."
  1272. (interactive "p")
  1273. ;; To remove any deleted diary entries. Do not redraw when:
  1274. ;; i) processing #include diary files (else only get the marks from
  1275. ;; the last #include file processed).
  1276. ;; ii) called via calendar-redraw (since calendar has already been
  1277. ;; erased).
  1278. ;; Use of REDRAW handles both of these cases.
  1279. (when (and redraw calendar-mark-diary-entries-flag)
  1280. (setq calendar-mark-diary-entries-flag nil)
  1281. (calendar-redraw))
  1282. (let ((diary-marking-entries-flag t)
  1283. (diary-buffer (find-buffer-visiting diary-file))
  1284. ;; Dynamically bound in diary-include-files.
  1285. (d-incp (and (boundp 'diary-including) diary-including))
  1286. file-glob-attrs temp-buff)
  1287. (unless d-incp
  1288. (setq diary-included-files nil)
  1289. (message "Marking diary entries..."))
  1290. (unwind-protect
  1291. (with-current-buffer (or diary-buffer
  1292. (if d-incp
  1293. (setq temp-buff (generate-new-buffer
  1294. " *diary-temp*"))
  1295. (find-file-noselect
  1296. (diary-check-diary-file) t)))
  1297. (if temp-buff
  1298. ;; If including, caller has already verified it is readable.
  1299. (insert-file-contents diary-file)
  1300. (if (eq major-mode (default-value 'major-mode)) (diary-mode)))
  1301. (setq calendar-mark-diary-entries-flag t)
  1302. (setq file-glob-attrs (nth 1 (diary-pull-attrs nil '())))
  1303. (with-syntax-table diary-syntax-table
  1304. (save-excursion
  1305. (diary-mark-entries-1 'calendar-mark-date-pattern)
  1306. (diary-mark-sexp-entries)
  1307. ;; Although it looks like mark-entries-hook runs every time,
  1308. ;; diary-mark-included-diary-files binds it to nil
  1309. ;; (essentially) when it runs in included files.
  1310. (run-hooks 'diary-nongregorian-marking-hook
  1311. 'diary-mark-entries-hook))))
  1312. (and temp-buff (buffer-name temp-buff) (kill-buffer temp-buff)))
  1313. (or d-incp (message "Marking diary entries...done"))))
  1314. ;;;###cal-autoload
  1315. (define-obsolete-function-alias 'mark-diary-entries 'diary-mark-entries "23.1")
  1316. (defun diary-sexp-entry (sexp entry date)
  1317. "Process a SEXP diary ENTRY for DATE."
  1318. (let ((result (if calendar-debug-sexp
  1319. (let ((debug-on-error t))
  1320. (eval (car (read-from-string sexp))))
  1321. (condition-case nil
  1322. (eval (car (read-from-string sexp)))
  1323. (error
  1324. (beep)
  1325. (message "Bad sexp at line %d in %s: %s"
  1326. (count-lines (point-min) (point))
  1327. diary-file sexp)
  1328. (sleep-for 2))))))
  1329. (cond ((stringp result) result)
  1330. ((and (consp result)
  1331. (stringp (cdr result))) result)
  1332. (result entry)
  1333. (t nil))))
  1334. (defvar displayed-year) ; bound in calendar-generate
  1335. (defvar displayed-month)
  1336. (defun diary-mark-sexp-entries ()
  1337. "Mark days in the calendar window that have sexp diary entries.
  1338. Each entry in the diary file (or included files) visible in the calendar window
  1339. is marked. See the documentation for the function `diary-list-sexp-entries'."
  1340. (let* ((sexp-mark (regexp-quote diary-sexp-entry-symbol))
  1341. (s-entry (format "^\\(%s(\\)\\|\\(%s%s(diary-remind\\)" sexp-mark
  1342. (regexp-quote diary-nonmarking-symbol)
  1343. sexp-mark))
  1344. (file-glob-attrs (nth 1 (diary-pull-attrs nil '())))
  1345. m y first-date last-date date mark file-glob-attrs
  1346. sexp-start sexp entry entry-start)
  1347. (with-current-buffer calendar-buffer
  1348. (setq m displayed-month
  1349. y displayed-year))
  1350. (calendar-increment-month m y -1)
  1351. (setq first-date (calendar-absolute-from-gregorian (list m 1 y)))
  1352. (calendar-increment-month m y 2)
  1353. (setq last-date
  1354. (calendar-absolute-from-gregorian
  1355. (list m (calendar-last-day-of-month m y) y)))
  1356. (goto-char (point-min))
  1357. (while (re-search-forward s-entry nil t)
  1358. (setq diary-marking-entry-flag (char-equal (preceding-char) ?\())
  1359. (re-search-backward "(")
  1360. (setq sexp-start (point))
  1361. (forward-sexp)
  1362. (setq sexp (buffer-substring-no-properties sexp-start (point)))
  1363. (forward-char 1)
  1364. (if (and (bolp) (not (looking-at "[ \t]")))
  1365. ;; Diary entry consists only of the sexp.
  1366. (progn
  1367. (backward-char 1)
  1368. (setq entry ""))
  1369. (setq entry-start (point))
  1370. ;; Find end of entry.
  1371. (forward-line 1)
  1372. (while (looking-at "[ \t]")
  1373. (forward-line 1))
  1374. (if (bolp) (backward-char 1))
  1375. (setq entry (buffer-substring-no-properties entry-start (point))))
  1376. (setq date (1- first-date))
  1377. ;; FIXME this loops over all visible dates.
  1378. ;; Could be optimized in many cases. Depends on whether t or * present.
  1379. (while (<= (setq date (1+ date)) last-date)
  1380. (when (setq mark (diary-sexp-entry
  1381. sexp entry
  1382. (calendar-gregorian-from-absolute date)))
  1383. (calendar-mark-visible-date
  1384. (calendar-gregorian-from-absolute date)
  1385. (or (cadr (diary-pull-attrs entry file-glob-attrs))
  1386. (if (consp mark) (car mark)))))))))
  1387. (define-obsolete-function-alias 'mark-sexp-diary-entries
  1388. 'diary-mark-sexp-entries "23.1")
  1389. (defun diary-mark-included-diary-files ()
  1390. "Mark diary entries from included diary files.
  1391. To use, add this function to `diary-mark-entries-hook'.
  1392. For details, see `diary-include-files'.
  1393. See also `diary-include-other-diary-files'."
  1394. (diary-include-files t))
  1395. (define-obsolete-function-alias 'mark-included-diary-files
  1396. 'diary-mark-included-diary-files "23.1")
  1397. (defun calendar-mark-days-named (dayname &optional color)
  1398. "Mark all dates in the calendar window that are day DAYNAME of the week.
  1399. 0 means all Sundays, 1 means all Mondays, and so on.
  1400. Optional argument COLOR is passed to `calendar-mark-visible-date' as MARK."
  1401. (with-current-buffer calendar-buffer
  1402. (let ((prev-month displayed-month)
  1403. (prev-year displayed-year)
  1404. (succ-month displayed-month)
  1405. (succ-year displayed-year)
  1406. (last-day)
  1407. (day))
  1408. (calendar-increment-month succ-month succ-year 1)
  1409. (calendar-increment-month prev-month prev-year -1)
  1410. (setq day (calendar-absolute-from-gregorian
  1411. (calendar-nth-named-day 1 dayname prev-month prev-year))
  1412. last-day (calendar-absolute-from-gregorian
  1413. (calendar-nth-named-day -1 dayname succ-month succ-year)))
  1414. (while (<= day last-day)
  1415. (calendar-mark-visible-date (calendar-gregorian-from-absolute day)
  1416. color)
  1417. (setq day (+ day 7))))))
  1418. (define-obsolete-function-alias 'mark-calendar-days-named
  1419. 'calendar-mark-days-named "23.1")
  1420. (defun calendar-mark-month (month year p-month p-day p-year &optional color)
  1421. "Mark dates in the MONTH/YEAR that conform to pattern P-MONTH/P-DAY/P-YEAR.
  1422. A value of 0 in any position of the pattern is a wildcard.
  1423. Optional argument COLOR is passed to `calendar-mark-visible-date' as MARK."
  1424. (if (or (and (= month p-month)
  1425. (or (zerop p-year) (= year p-year)))
  1426. (and (zerop p-month)
  1427. (or (zerop p-year) (= year p-year))))
  1428. (if (zerop p-day)
  1429. (dotimes (i (calendar-last-day-of-month month year))
  1430. (calendar-mark-visible-date (list month (1+ i) year) color))
  1431. (calendar-mark-visible-date (list month p-day year) color))))
  1432. (define-obsolete-function-alias 'mark-calendar-month
  1433. 'calendar-mark-month "23.1")
  1434. (defun calendar-mark-date-pattern (month day year &optional color)
  1435. "Mark all dates in the calendar window that conform to MONTH/DAY/YEAR.
  1436. A value of 0 in any position is a wildcard. Optional argument COLOR is
  1437. passed to `calendar-mark-visible-date' as MARK."
  1438. (with-current-buffer calendar-buffer
  1439. (let ((m displayed-month)
  1440. (y displayed-year))
  1441. (calendar-increment-month m y -1)
  1442. (dotimes (_idummy 3)
  1443. (calendar-mark-month m y month day year color)
  1444. (calendar-increment-month m y 1)))))
  1445. (define-obsolete-function-alias 'mark-calendar-date-pattern
  1446. 'calendar-mark-date-pattern "23.1")
  1447. ;; Bahai, Hebrew, Islamic.
  1448. (defun calendar-mark-complex (month day year fromabs &optional color)
  1449. "Mark dates in the calendar conforming to MONTH DAY YEAR of some system.
  1450. The function FROMABS converts absolute dates to the appropriate date system.
  1451. Optional argument COLOR is passed to `calendar-mark-visible-date' as MARK."
  1452. ;; Not one of the simple cases--check all visible dates for match.
  1453. ;; Actually, the following code takes care of ALL of the cases, but
  1454. ;; it's much too slow to be used for the simple (common) cases.
  1455. (let* ((m displayed-month)
  1456. (y displayed-year)
  1457. (first-date (progn
  1458. (calendar-increment-month m y -1)
  1459. (calendar-absolute-from-gregorian (list m 1 y))))
  1460. (last-date (progn
  1461. (calendar-increment-month m y 2)
  1462. (calendar-absolute-from-gregorian
  1463. (list m (calendar-last-day-of-month m y) y))))
  1464. (date (1- first-date))
  1465. local-date)
  1466. (while (<= (setq date (1+ date)) last-date)
  1467. (setq local-date (funcall fromabs date))
  1468. (and (or (zerop month)
  1469. (= month (calendar-extract-month local-date)))
  1470. (or (zerop day)
  1471. (= day (calendar-extract-day local-date)))
  1472. (or (zerop year)
  1473. (= year (calendar-extract-year local-date)))
  1474. (calendar-mark-visible-date
  1475. (calendar-gregorian-from-absolute date) color)))))
  1476. ;; Bahai, Islamic.
  1477. (defun calendar-mark-1 (month day year fromabs toabs &optional color)
  1478. "Mark dates in the calendar conforming to MONTH DAY YEAR of some system.
  1479. The function FROMABS converts absolute dates to the appropriate date system.
  1480. The function TOABS carries out the inverse operation. Optional argument
  1481. COLOR is passed to `calendar-mark-visible-date' as MARK."
  1482. (with-current-buffer calendar-buffer
  1483. (if (and (not (zerop month)) (not (zerop day)))
  1484. (if (not (zerop year))
  1485. ;; Fully specified date.
  1486. (let ((date (calendar-gregorian-from-absolute
  1487. (funcall toabs (list month day year)))))
  1488. (if (calendar-date-is-visible-p date)
  1489. (calendar-mark-visible-date date color)))
  1490. ;; Month and day in any year--this taken from the holiday stuff.
  1491. (let* ((i-date (funcall fromabs
  1492. (calendar-absolute-from-gregorian
  1493. (list displayed-month 15 displayed-year))))
  1494. (m (calendar-extract-month i-date))
  1495. (y (calendar-extract-year i-date))
  1496. date)
  1497. (unless (< m 1) ; calendar doesn't apply
  1498. (calendar-increment-month m y (- 10 month))
  1499. (and (> m 7) ; date might be visible
  1500. (calendar-date-is-visible-p
  1501. (setq date (calendar-gregorian-from-absolute
  1502. (funcall toabs (list month day y)))))
  1503. (calendar-mark-visible-date date color)))))
  1504. (calendar-mark-complex month day year
  1505. 'calendar-bahai-from-absolute color))))
  1506. (defun diary-entry-time (s)
  1507. "Return time at the beginning of the string S as a military-style integer.
  1508. For example, returns 1325 for 1:25pm.
  1509. Returns `diary-unknown-time' (default value -9999) if no time is recognized.
  1510. The recognized forms are XXXX, X:XX, or XX:XX (military time), and XXam,
  1511. XXAM, XXpm, XXPM, XX:XXam, XX:XXAM, XX:XXpm, or XX:XXPM. A period (.) can
  1512. be used instead of a colon (:) to separate the hour and minute parts."
  1513. (let (case-fold-search)
  1514. (cond ((string-match ; military time
  1515. "\\`[ \t\n]*\\([0-9]?[0-9]\\)[:.]?\\([0-9][0-9]\\)\\(\\>\\|[^ap]\\)"
  1516. s)
  1517. (+ (* 100 (string-to-number (match-string 1 s)))
  1518. (string-to-number (match-string 2 s))))
  1519. ((string-match ; hour only (XXam or XXpm)
  1520. "\\`[ \t\n]*\\([0-9]?[0-9]\\)\\([ap]\\)m\\>" s)
  1521. (+ (* 100 (% (string-to-number (match-string 1 s)) 12))
  1522. (if (equal ?a (downcase (aref s (match-beginning 2))))
  1523. 0 1200)))
  1524. ((string-match ; hour and minute (XX:XXam or XX:XXpm)
  1525. "\\`[ \t\n]*\\([0-9]?[0-9]\\)[:.]\\([0-9][0-9]\\)\\([ap]\\)m\\>" s)
  1526. (+ (* 100 (% (string-to-number (match-string 1 s)) 12))
  1527. (string-to-number (match-string 2 s))
  1528. (if (equal ?a (downcase (aref s (match-beginning 3))))
  1529. 0 1200)))
  1530. (t diary-unknown-time)))) ; unrecognizable
  1531. (defun diary-entry-compare (e1 e2)
  1532. "Return t if E1 is earlier than E2."
  1533. (or (calendar-date-compare e1 e2)
  1534. (and (calendar-date-equal (car e1) (car e2))
  1535. (let* ((ts1 (cadr e1)) (t1 (diary-entry-time ts1))
  1536. (ts2 (cadr e2)) (t2 (diary-entry-time ts2)))
  1537. (or (< t1 t2)
  1538. (and (= t1 t2)
  1539. (string-lessp ts1 ts2)))))))
  1540. (defun diary-sort-entries ()
  1541. "Sort the list of diary entries by time of day.
  1542. If you add this function to `diary-list-entries-hook', it should
  1543. be the last item in the hook, in case earlier items add diary
  1544. entries, or change the order."
  1545. (setq diary-entries-list (sort diary-entries-list 'diary-entry-compare)))
  1546. (define-obsolete-function-alias 'sort-diary-entries 'diary-sort-entries "23.1")
  1547. (defun diary-list-sexp-entries (date)
  1548. "Add sexp entries for DATE from the diary file to `diary-entries-list'.
  1549. Also, make them visible in the diary. Returns t if any entries are found.
  1550. Sexp diary entries must be prefaced by a `diary-sexp-entry-symbol'
  1551. \(normally `%%'). The form of a sexp diary entry is
  1552. %%(SEXP) ENTRY
  1553. Both ENTRY and DATE are available when the SEXP is evaluated. If
  1554. the SEXP returns nil, the diary entry does not apply. If it
  1555. returns a non-nil value, ENTRY will be taken to apply to DATE; if
  1556. the value is a string, that string will be the diary entry in the
  1557. fancy diary display.
  1558. For example, the following diary entry will apply to the 21st of
  1559. the month if it is a weekday and the Friday before if the 21st is
  1560. on a weekend:
  1561. &%%(let ((dayname (calendar-day-of-week date))
  1562. (day (calendar-extract-day date)))
  1563. (or
  1564. (and (= day 21) (memq dayname '(1 2 3 4 5)))
  1565. (and (memq day '(19 20)) (= dayname 5)))
  1566. ) UIUC pay checks deposited
  1567. A number of built-in functions are available for this type of
  1568. diary entry. In the following, the optional parameter MARK
  1569. specifies a face or single-character string to use when
  1570. highlighting the day in the calendar. For those functions that
  1571. take MONTH, DAY, and YEAR as arguments, the order of the input
  1572. parameters changes according to `calendar-date-style' (e.g. to
  1573. DAY MONTH YEAR in the European style).
  1574. %%(diary-date MONTH DAY YEAR &optional MARK) text
  1575. Entry applies if date is MONTH, DAY, YEAR. DAY, MONTH, and YEAR can
  1576. be a list of integers, `t' (meaning all values), or an integer.
  1577. %%(diary-float MONTH DAYNAME N &optional DAY MARK) text
  1578. Entry will appear on the Nth DAYNAME after/before MONTH DAY.
  1579. DAYNAME=0 means Sunday, DAYNAME=1 means Monday, and so on.
  1580. If N>0, use the Nth DAYNAME after MONTH DAY.
  1581. If N<0, use the Nth DAYNAME before MONTH DAY.
  1582. DAY defaults to 1 if N>0, and MONTH's last day otherwise.
  1583. MONTH can be a list of months, a single month, or `t' to
  1584. specify all months.
  1585. %%(diary-block M1 D1 Y1 M2 D2 Y2 &optional MARK) text
  1586. Entry will appear on dates between M1/D1/Y1 and M2/D2/Y2,
  1587. inclusive.
  1588. %%(diary-anniversary MONTH DAY YEAR &optional MARK) text
  1589. Entry will appear on anniversary dates of MONTH DAY, YEAR.
  1590. Text can contain `%d' or `%d%s'; `%d' will be replaced by the
  1591. number of years since the MONTH DAY, YEAR, and `%s' by the
  1592. ordinal ending of that number (i.e. `st', `nd', `rd' or `th',
  1593. as appropriate). The anniversary of February 29 is
  1594. considered to be March 1 in a non-leap year.
  1595. %%(diary-cyclic N MONTH DAY YEAR &optional MARK) text
  1596. Entry will appear every N days, starting MONTH DAY, YEAR.
  1597. Text can contain `%d' or `%d%s'; `%d' will be replaced by the
  1598. number of repetitions since the MONTH DAY, YEAR and `%s' by
  1599. the ordinal ending of that number (i.e. `st', `nd', `rd' or
  1600. `th', as appropriate).
  1601. %%(diary-remind SEXP DAYS &optional MARKING) text
  1602. Entry is a reminder for diary sexp SEXP. DAYS is either a
  1603. single number or a list of numbers indicating the number(s)
  1604. of days before the event that the warning(s) should occur.
  1605. A negative number -DAYS has the same meaning as a list (1 2 ... DAYS).
  1606. If the current date is (one of) DAYS before the event indicated
  1607. by EXPR, then a suitable message (as specified by
  1608. `diary-remind-message') appears. In addition to the
  1609. reminders beforehand, the diary entry also appears on the
  1610. date itself. If optional MARKING is non-nil then the
  1611. *reminders* are marked on the calendar. Marking of reminders
  1612. is independent of whether the entry *itself* is a marking or
  1613. non-marking one.
  1614. %%(diary-hebrew-yahrzeit MONTH DAY YEAR) text
  1615. Text is assumed to be the name of the person; the date is the
  1616. date of death on the *civil* calendar. The diary entry will
  1617. appear on the proper Hebrew-date anniversary and on the day
  1618. before.
  1619. All the remaining functions do not accept any text, and so only
  1620. make sense with `diary-fancy-display'. Most produce output every day.
  1621. `diary-day-of-year' - day of year and number of days remaining
  1622. `diary-iso-date' - ISO commercial date
  1623. `diary-astro-day-number' - astronomical (Julian) day number
  1624. `diary-sunrise-sunset' - local times of sunrise and sunset
  1625. These functions give the date in alternative calendrical systems:
  1626. `diary-bahai-date', `diary-chinese-date', `diary-coptic-date',
  1627. `diary-ethiopic-date', `diary-french-date', `diary-hebrew-date',
  1628. `diary-islamic-date', `diary-julian-date', `diary-mayan-date',
  1629. `diary-persian-date'
  1630. Theses functions only produce output on certain dates:
  1631. `diary-lunar-phases' - phases of moon (on the appropriate days)
  1632. `diary-hebrew-omer' - Omer count, within 50 days after Passover
  1633. `diary-hebrew-parasha' - weekly parasha, every Saturday
  1634. `diary-hebrew-rosh-hodesh' - Rosh Hodesh, or the day or Saturday before
  1635. `diary-hebrew-sabbath-candles' - local time of candle lighting, on Fridays
  1636. Marking these entries is *extremely* time consuming, so it is
  1637. best if they are non-marking."
  1638. (let ((s-entry (format "^%s?%s(" (regexp-quote diary-nonmarking-symbol)
  1639. (regexp-quote diary-sexp-entry-symbol)))
  1640. entry-found file-glob-attrs marks
  1641. sexp-start sexp entry specifier entry-start line-start
  1642. diary-entry temp literal)
  1643. (goto-char (point-min))
  1644. (setq file-glob-attrs (nth 1 (diary-pull-attrs nil '())))
  1645. (while (re-search-forward s-entry nil t)
  1646. (backward-char 1)
  1647. (setq sexp-start (point))
  1648. (forward-sexp)
  1649. (setq sexp (buffer-substring-no-properties sexp-start (point))
  1650. line-start (line-end-position 0)
  1651. specifier
  1652. (buffer-substring-no-properties (1+ line-start) (point))
  1653. entry-start (1+ line-start))
  1654. (forward-char 1)
  1655. (if (and (bolp) (not (looking-at "[ \t]")))
  1656. ;; Diary entry consists only of the sexp.
  1657. (progn
  1658. (backward-char 1)
  1659. (setq entry ""))
  1660. (setq entry-start (point))
  1661. (forward-line 1)
  1662. (while (looking-at "[ \t]")
  1663. (forward-line 1))
  1664. (if (bolp) (backward-char 1))
  1665. (setq entry (buffer-substring-no-properties entry-start (point))))
  1666. (setq diary-entry (diary-sexp-entry sexp entry date)
  1667. literal entry ; before evaluation
  1668. entry (if (consp diary-entry)
  1669. (cdr diary-entry)
  1670. diary-entry))
  1671. (when diary-entry
  1672. (remove-overlays line-start (point) 'invisible 'diary)
  1673. (if (< 0 (length entry))
  1674. (setq temp (diary-pull-attrs entry file-glob-attrs)
  1675. entry (nth 0 temp)
  1676. marks (nth 1 temp))))
  1677. (diary-add-to-list date entry specifier
  1678. (if entry-start (copy-marker entry-start))
  1679. marks literal)
  1680. (setq entry-found (or entry-found diary-entry)))
  1681. entry-found))
  1682. (define-obsolete-function-alias 'list-sexp-diary-entries
  1683. 'diary-list-sexp-entries "23.1")
  1684. (defun diary-make-date (a b c)
  1685. "Convert A B C into the internal calendar date form.
  1686. The expected order of the inputs depends on `calendar-date-style',
  1687. e.g. in the European case, A = day, B = month, C = year. Returns
  1688. a list (MONTH DAY YEAR), i.e. the American style, which is the
  1689. form used internally by the calendar and diary."
  1690. (cond ((eq calendar-date-style 'iso) ; YMD
  1691. (list b c a))
  1692. ((eq calendar-date-style 'european) ; DMY
  1693. (list b a c))
  1694. (t (list a b c))))
  1695. ;;; Sexp diary functions.
  1696. (defvar date)
  1697. (defvar entry)
  1698. ;; To be called from diary-sexp-entry, where DATE, ENTRY are bound.
  1699. (defun diary-date (month day year &optional mark)
  1700. "Specific date(s) diary entry.
  1701. Entry applies if date is MONTH, DAY, YEAR. Each parameter can be a
  1702. list of integers, `t' (meaning all values), or an integer. The order
  1703. of the input parameters changes according to `calendar-date-style'
  1704. \(e.g. to DAY MONTH YEAR in the European style).
  1705. An optional parameter MARK specifies a face or single-character string
  1706. to use when highlighting the day in the calendar."
  1707. (let* ((ddate (diary-make-date month day year))
  1708. (dd (calendar-extract-day ddate))
  1709. (mm (calendar-extract-month ddate))
  1710. (yy (calendar-extract-year ddate))
  1711. (m (calendar-extract-month date))
  1712. (y (calendar-extract-year date))
  1713. (d (calendar-extract-day date)))
  1714. (and
  1715. (or (and (listp dd) (memq d dd))
  1716. (equal d dd)
  1717. (eq dd t))
  1718. (or (and (listp mm) (memq m mm))
  1719. (equal m mm)
  1720. (eq mm t))
  1721. (or (and (listp yy) (memq y yy))
  1722. (equal y yy)
  1723. (eq yy t))
  1724. (cons mark entry))))
  1725. ;; To be called from diary-sexp-entry, where DATE, ENTRY are bound.
  1726. (defun diary-block (m1 d1 y1 m2 d2 y2 &optional mark)
  1727. "Block diary entry.
  1728. Entry applies if date is between, or on one of, two dates. The order
  1729. of the input parameters changes according to `calendar-date-style'
  1730. \(e.g. to D1, M1, Y1, D2, M2, Y2 in the European style).
  1731. An optional parameter MARK specifies a face or single-character string
  1732. to use when highlighting the day in the calendar."
  1733. (let ((date1 (calendar-absolute-from-gregorian
  1734. (diary-make-date m1 d1 y1)))
  1735. (date2 (calendar-absolute-from-gregorian
  1736. (diary-make-date m2 d2 y2)))
  1737. (d (calendar-absolute-from-gregorian date)))
  1738. (and (<= date1 d) (<= d date2)
  1739. (cons mark entry))))
  1740. ;; To be called from diary-sexp-entry, where DATE, ENTRY are bound.
  1741. (defun diary-float (month dayname n &optional day mark)
  1742. "Diary entry for the Nth DAYNAME after/before MONTH DAY.
  1743. DAYNAME=0 means Sunday, DAYNAME=1 means Monday, and so on.
  1744. If N>0, use the Nth DAYNAME after MONTH DAY.
  1745. If N<0, use the Nth DAYNAME before MONTH DAY.
  1746. DAY defaults to 1 if N>0, and MONTH's last day otherwise.
  1747. MONTH can be a list of months, an integer, or `t' (meaning all months).
  1748. Optional MARK specifies a face or single-character string to use when
  1749. highlighting the day in the calendar."
  1750. ;; This is messy because the diary entry may apply, but the date on which it
  1751. ;; is based can be in a different month/year. For example, asking for the
  1752. ;; first Monday after December 30. For large values of |n| the problem is
  1753. ;; more grotesque.
  1754. (and (= dayname (calendar-day-of-week date))
  1755. (let* ((m (calendar-extract-month date))
  1756. (d (calendar-extract-day date))
  1757. (y (calendar-extract-year date))
  1758. ;; Last (n>0) or first (n<0) possible base date for entry.
  1759. (limit
  1760. (calendar-nth-named-absday (- n) dayname m y d))
  1761. (last-abs (if (> n 0) limit (+ limit 6)))
  1762. (first-abs (if (> n 0) (- limit 6) limit))
  1763. (last (calendar-gregorian-from-absolute last-abs))
  1764. (first (calendar-gregorian-from-absolute first-abs))
  1765. ;; m1, d1 is first possible base date.
  1766. (m1 (calendar-extract-month first))
  1767. (d1 (calendar-extract-day first))
  1768. (y1 (calendar-extract-year first))
  1769. ;; m2, d2 is last possible base date.
  1770. (m2 (calendar-extract-month last))
  1771. (d2 (calendar-extract-day last))
  1772. (y2 (calendar-extract-year last)))
  1773. (if (or (and (= m1 m2) ; only possible base dates in one month
  1774. (or (eq month t)
  1775. (if (listp month)
  1776. (memq m1 month)
  1777. (= m1 month)))
  1778. (let ((d (or day (if (> n 0)
  1779. 1
  1780. (calendar-last-day-of-month m1 y1)))))
  1781. (and (<= d1 d) (<= d d2))))
  1782. ;; Only possible base dates straddle two months.
  1783. (and (or (< y1 y2)
  1784. (and (= y1 y2) (< m1 m2)))
  1785. (or
  1786. ;; m1, d1 works as a base date.
  1787. (and
  1788. (or (eq month t)
  1789. (if (listp month)
  1790. (memq m1 month)
  1791. (= m1 month)))
  1792. (<= d1 (or day (if (> n 0)
  1793. 1
  1794. (calendar-last-day-of-month m1 y1)))))
  1795. ;; m2, d2 works as a base date.
  1796. (and (or (eq month t)
  1797. (if (listp month)
  1798. (memq m2 month)
  1799. (= m2 month)))
  1800. (<= (or day (if (> n 0)
  1801. 1
  1802. (calendar-last-day-of-month m2 y2)))
  1803. d2)))))
  1804. (cons mark entry)))))
  1805. (defun diary-ordinal-suffix (n)
  1806. "Ordinal suffix for N. (That is, `st', `nd', `rd', or `th', as appropriate.)"
  1807. (if (or (memq (% n 100) '(11 12 13))
  1808. (< 3 (% n 10)))
  1809. "th"
  1810. (aref ["th" "st" "nd" "rd"] (% n 10))))
  1811. ;; To be called from diary-sexp-entry, where DATE, ENTRY are bound.
  1812. (defun diary-anniversary (month day &optional year mark)
  1813. "Anniversary diary entry.
  1814. Entry applies if date is the anniversary of MONTH, DAY, YEAR.
  1815. The order of the input parameters changes according to
  1816. `calendar-date-style' (e.g. to DAY MONTH YEAR in the European style).
  1817. The diary entry can contain `%d' or `%d%s'; the %d will be replaced
  1818. by the number of years since the MONTH, DAY, YEAR, and the %s will
  1819. be replaced by the ordinal ending of that number (that is, `st',
  1820. `nd', `rd' or `th', as appropriate). The anniversary of February 29
  1821. is considered to be March 1 in non-leap years.
  1822. An optional parameter MARK specifies a face or single-character
  1823. string to use when highlighting the day in the calendar."
  1824. (let* ((ddate (diary-make-date month day year))
  1825. (dd (calendar-extract-day ddate))
  1826. (mm (calendar-extract-month ddate))
  1827. (yy (calendar-extract-year ddate))
  1828. (y (calendar-extract-year date))
  1829. (diff (if yy (- y yy) 100)))
  1830. (and (= mm 2) (= dd 29) (not (calendar-leap-year-p y))
  1831. (setq mm 3
  1832. dd 1))
  1833. (and (> diff 0) (calendar-date-equal (list mm dd y) date)
  1834. (cons mark (format entry diff (diary-ordinal-suffix diff))))))
  1835. ;; To be called from diary-sexp-entry, where DATE, ENTRY are bound.
  1836. (defun diary-cyclic (n month day year &optional mark)
  1837. "Cycle diary entry--entry applies every N days starting at MONTH, DAY, YEAR.
  1838. The order of the input parameters changes according to
  1839. `calendar-date-style' (e.g. to N DAY MONTH YEAR in the European
  1840. style). The entry can contain `%d' or `%d%s'; the %d will be
  1841. replaced by the number of repetitions since the MONTH DAY YEAR,
  1842. and %s by the ordinal ending of that number (that is, `st', `nd',
  1843. `rd' or `th', as appropriate).
  1844. An optional parameter MARK specifies a face or single-character
  1845. string to use when highlighting the day in the calendar."
  1846. (or (> n 0)
  1847. (error "Day count must be positive"))
  1848. (let* ((diff (- (calendar-absolute-from-gregorian date)
  1849. (calendar-absolute-from-gregorian
  1850. (diary-make-date month day year))))
  1851. (cycle (/ diff n)))
  1852. (and (>= diff 0) (zerop (% diff n))
  1853. (cons mark (format entry cycle (diary-ordinal-suffix cycle))))))
  1854. (defun diary-day-of-year ()
  1855. "Day of year and number of days remaining in the year of date diary entry."
  1856. (calendar-day-of-year-string date))
  1857. (defun diary-remind (sexp days &optional marking)
  1858. "Provide a reminder of a diary entry.
  1859. SEXP is a diary-sexp. DAYS is either a single number or a list
  1860. of numbers indicating the number(s) of days before the event that
  1861. the warning(s) should occur on. A negative number -DAYS has the
  1862. same meaning as a list (1 2 ... DAYS). If the current date
  1863. is (one of) DAYS before the event indicated by SEXP, then this function
  1864. returns a suitable message (as specified by `diary-remind-message').
  1865. In addition to the reminders beforehand, the diary entry also
  1866. appears on the date itself.
  1867. A `diary-nonmarking-symbol' at the beginning of the line of the
  1868. `diary-remind' entry specifies that the diary entry (not the
  1869. reminder) is non-marking. Marking of reminders is independent of
  1870. whether the entry itself is a marking or nonmarking; if optional
  1871. parameter MARKING is non-nil then the reminders are marked on the
  1872. calendar."
  1873. ;; `date' has a value at this point, from diary-sexp-entry.
  1874. ;; Convert a negative number to a list of days.
  1875. (and (integerp days)
  1876. (< days 0)
  1877. (setq days (number-sequence 1 (- days))))
  1878. (let ((diary-entry (eval sexp)))
  1879. (cond
  1880. ;; Diary entry applies on date.
  1881. ((and diary-entry
  1882. (or (not diary-marking-entries-flag) diary-marking-entry-flag))
  1883. diary-entry)
  1884. ;; Diary entry may apply to `days' before date.
  1885. ((and (integerp days)
  1886. (not diary-entry) ; diary entry does not apply to date
  1887. (or (not diary-marking-entries-flag) marking))
  1888. ;; Adjust date, and re-evaluate.
  1889. (let ((date (calendar-gregorian-from-absolute
  1890. (+ (calendar-absolute-from-gregorian date) days))))
  1891. (when (setq diary-entry (eval sexp))
  1892. ;; Discard any mark portion from diary-anniversary, etc.
  1893. (if (consp diary-entry) (setq diary-entry (cdr diary-entry)))
  1894. (mapconcat 'eval diary-remind-message ""))))
  1895. ;; Diary entry may apply to one of a list of days before date.
  1896. ((and (listp days) days)
  1897. (or (diary-remind sexp (car days) marking)
  1898. (diary-remind sexp (cdr days) marking))))))
  1899. ;;; Diary insertion functions.
  1900. ;;;###cal-autoload
  1901. (defun diary-make-entry (string &optional nonmarking file)
  1902. "Insert a diary entry STRING which may be NONMARKING in FILE.
  1903. If omitted, NONMARKING defaults to nil and FILE defaults to
  1904. `diary-file'."
  1905. (let ((pop-up-frames (or pop-up-frames
  1906. (window-dedicated-p (selected-window)))))
  1907. (find-file-other-window (or file diary-file)))
  1908. (when (eq major-mode (default-value 'major-mode)) (diary-mode))
  1909. (widen)
  1910. (diary-unhide-everything)
  1911. (goto-char (point-max))
  1912. (when (let ((case-fold-search t))
  1913. (search-backward "Local Variables:"
  1914. (max (- (point-max) 3000) (point-min))
  1915. t))
  1916. (beginning-of-line)
  1917. (insert "\n")
  1918. (forward-line -1))
  1919. (insert
  1920. (if (bolp) "" "\n")
  1921. (if nonmarking diary-nonmarking-symbol "")
  1922. string " "))
  1923. ;;;###cal-autoload
  1924. (define-obsolete-function-alias 'make-diary-entry 'diary-make-entry "23.1")
  1925. ;;;###cal-autoload
  1926. (defun diary-insert-entry (arg &optional event)
  1927. "Insert a diary entry for the date indicated by point.
  1928. Prefix argument ARG makes the entry nonmarking."
  1929. (interactive
  1930. (list current-prefix-arg last-nonmenu-event))
  1931. (diary-make-entry (calendar-date-string (calendar-cursor-to-date t event) t t)
  1932. arg))
  1933. ;;;###cal-autoload
  1934. (define-obsolete-function-alias 'insert-diary-entry 'diary-insert-entry "23.1")
  1935. ;;;###cal-autoload
  1936. (defun diary-insert-weekly-entry (arg)
  1937. "Insert a weekly diary entry for the day of the week indicated by point.
  1938. Prefix argument ARG makes the entry nonmarking."
  1939. (interactive "P")
  1940. (diary-make-entry (calendar-day-name (calendar-cursor-to-date t))
  1941. arg))
  1942. ;;;###cal-autoload
  1943. (define-obsolete-function-alias 'insert-weekly-diary-entry
  1944. 'diary-insert-weekly-entry "23.1")
  1945. (defun diary-date-display-form (&optional type)
  1946. "Return value for `calendar-date-display-form' using `calendar-date-style'.
  1947. Optional symbol TYPE is either `monthly' or `yearly'."
  1948. (cond ((eq type 'monthly) (cond ((eq calendar-date-style 'iso)
  1949. '((format "*-*-%.2d"
  1950. (string-to-number day))))
  1951. ((eq calendar-date-style 'european)
  1952. '(day " * "))
  1953. (t '("* " day ))))
  1954. ((eq type 'yearly) (cond ((eq calendar-date-style 'iso)
  1955. '((format "*-%.2d-%.2d"
  1956. (string-to-number month)
  1957. (string-to-number day))))
  1958. ((eq calendar-date-style 'european)
  1959. '(day " " monthname))
  1960. (t '(monthname " " day))))
  1961. ;; Iso cannot contain "-", because this form used eg by
  1962. ;; diary-insert-anniversary-entry.
  1963. (t (cond ((eq calendar-date-style 'iso)
  1964. '((format "%s %.2d %.2d" year
  1965. (string-to-number month) (string-to-number day))))
  1966. ((eq calendar-date-style 'european)
  1967. '(day " " month " " year))
  1968. (t '(month " " day " " year))))))
  1969. (defun diary-insert-entry-1 (&optional type nomark months symbol absfunc)
  1970. "Subroutine to insert a diary entry related to the date at point.
  1971. TYPE is the type of entry (`monthly' or `yearly'). NOMARK non-nil
  1972. means make the entry non-marking. Array MONTHS is used in place
  1973. of `calendar-month-name-array'. String SYMBOL marks the type of
  1974. diary entry. Function ABSFUNC converts absolute dates to dates of
  1975. the appropriate type."
  1976. (let ((calendar-date-display-form (if type
  1977. (diary-date-display-form type)
  1978. calendar-date-display-form))
  1979. (calendar-month-name-array (or months calendar-month-name-array))
  1980. (date (calendar-cursor-to-date t)))
  1981. (diary-make-entry
  1982. (format "%s%s" (or symbol "")
  1983. (calendar-date-string
  1984. (if absfunc
  1985. (funcall absfunc (calendar-absolute-from-gregorian date))
  1986. date)
  1987. (not absfunc)
  1988. (not type)))
  1989. nomark)))
  1990. ;;;###cal-autoload
  1991. (defun diary-insert-monthly-entry (arg)
  1992. "Insert a monthly diary entry for the day of the month indicated by point.
  1993. Prefix argument ARG makes the entry nonmarking."
  1994. (interactive "P")
  1995. (diary-insert-entry-1 'monthly arg))
  1996. ;;;###cal-autoload
  1997. (define-obsolete-function-alias 'insert-monthly-diary-entry
  1998. 'diary-insert-monthly-entry "23.1")
  1999. ;;;###cal-autoload
  2000. (defun diary-insert-yearly-entry (arg)
  2001. "Insert an annual diary entry for the day of the year indicated by point.
  2002. Prefix argument ARG makes the entry nonmarking."
  2003. (interactive "P")
  2004. (diary-insert-entry-1 'yearly arg))
  2005. ;;;###cal-autoload
  2006. (define-obsolete-function-alias 'insert-yearly-diary-entry
  2007. 'diary-insert-yearly-entry "23.1")
  2008. ;;;###cal-autoload
  2009. (defun diary-insert-anniversary-entry (arg)
  2010. "Insert an anniversary diary entry for the date given by point.
  2011. Prefix argument ARG makes the entry nonmarking."
  2012. (interactive "P")
  2013. (let ((calendar-date-display-form (diary-date-display-form)))
  2014. (diary-make-entry
  2015. (format "%s(diary-anniversary %s)"
  2016. diary-sexp-entry-symbol
  2017. (calendar-date-string (calendar-cursor-to-date t) nil t))
  2018. arg)))
  2019. ;;;###cal-autoload
  2020. (define-obsolete-function-alias 'insert-anniversary-diary-entry
  2021. 'diary-insert-anniversary-entry "23.1")
  2022. ;;;###cal-autoload
  2023. (defun diary-insert-block-entry (arg)
  2024. "Insert a block diary entry for the days between the point and marked date.
  2025. Prefix argument ARG makes the entry nonmarking."
  2026. (interactive "P")
  2027. (let ((calendar-date-display-form (diary-date-display-form))
  2028. (cursor (calendar-cursor-to-date t))
  2029. (mark (or (car calendar-mark-ring)
  2030. (error "No mark set in this buffer")))
  2031. start end)
  2032. (if (< (calendar-absolute-from-gregorian mark)
  2033. (calendar-absolute-from-gregorian cursor))
  2034. (setq start mark
  2035. end cursor)
  2036. (setq start cursor
  2037. end mark))
  2038. (diary-make-entry
  2039. (format "%s(diary-block %s %s)"
  2040. diary-sexp-entry-symbol
  2041. (calendar-date-string start nil t)
  2042. (calendar-date-string end nil t))
  2043. arg)))
  2044. ;;;###cal-autoload
  2045. (define-obsolete-function-alias 'insert-block-diary-entry
  2046. 'diary-insert-block-entry "23.1")
  2047. ;;;###cal-autoload
  2048. (defun diary-insert-cyclic-entry (arg)
  2049. "Insert a cyclic diary entry starting at the date given by point.
  2050. Prefix argument ARG makes the entry nonmarking."
  2051. (interactive "P")
  2052. (let ((calendar-date-display-form (diary-date-display-form)))
  2053. (diary-make-entry
  2054. (format "%s(diary-cyclic %d %s)"
  2055. diary-sexp-entry-symbol
  2056. (calendar-read "Repeat every how many days: "
  2057. (lambda (x) (> x 0)))
  2058. (calendar-date-string (calendar-cursor-to-date t) nil t))
  2059. arg)))
  2060. ;;;###cal-autoload
  2061. (define-obsolete-function-alias 'insert-cyclic-diary-entry
  2062. 'diary-insert-cyclic-entry "23.1")
  2063. ;;; Diary mode.
  2064. (defun diary-redraw-calendar ()
  2065. "If `calendar-buffer' is live and diary entries are marked, redraw it."
  2066. (and calendar-mark-diary-entries-flag
  2067. (save-excursion
  2068. (calendar-redraw)))
  2069. ;; Return value suitable for `write-contents-functions'.
  2070. nil)
  2071. (defvar diary-mode-map
  2072. (let ((map (make-sparse-keymap)))
  2073. (define-key map "\C-c\C-s" 'diary-show-all-entries)
  2074. (define-key map "\C-c\C-q" 'quit-window)
  2075. map)
  2076. "Keymap for `diary-mode'.")
  2077. (defun diary-font-lock-sexps (limit)
  2078. "Recognize sexp diary entry up to LIMIT for font-locking."
  2079. (if (re-search-forward
  2080. (format "^%s?\\(%s\\)" (regexp-quote diary-nonmarking-symbol)
  2081. (regexp-quote diary-sexp-entry-symbol))
  2082. limit t)
  2083. (condition-case nil
  2084. (save-restriction
  2085. (narrow-to-region (point-min) limit)
  2086. (let ((start (point)))
  2087. (forward-sexp 1)
  2088. (store-match-data (list start (point)))
  2089. t))
  2090. (error t))))
  2091. (defun diary-font-lock-date-forms (month-array &optional symbol abbrev-array)
  2092. "Create font-lock patterns for `diary-date-forms' using MONTH-ARRAY.
  2093. If given, optional SYMBOL must be a prefix to entries. If
  2094. optional ABBREV-ARRAY is present, also matches the abbreviations
  2095. from this array (with or without a final `.'), in addition to the
  2096. full month names."
  2097. (let ((dayname (diary-name-pattern calendar-day-name-array
  2098. calendar-day-abbrev-array t))
  2099. (monthname (format "\\(%s\\|\\*\\)"
  2100. (diary-name-pattern month-array abbrev-array)))
  2101. (month "\\([0-9]+\\|\\*\\)")
  2102. (day "\\([0-9]+\\|\\*\\)")
  2103. (year "-?\\([0-9]+\\|\\*\\)"))
  2104. (mapcar (lambda (x)
  2105. (cons
  2106. (concat "^" (regexp-quote diary-nonmarking-symbol) "?"
  2107. (if symbol (regexp-quote symbol) "") "\\("
  2108. (mapconcat 'eval
  2109. ;; If backup, omit first item (backup)
  2110. ;; and last item (not part of date).
  2111. (if (equal (car x) 'backup)
  2112. (nreverse (cdr (reverse (cdr x))))
  2113. x)
  2114. "")
  2115. ;; With backup, last item is not part of date.
  2116. (if (equal (car x) 'backup)
  2117. (concat "\\)" (eval (car (reverse x))))
  2118. "\\)"))
  2119. '(1 diary-face)))
  2120. diary-date-forms)))
  2121. (defmacro diary-font-lock-keywords-1 (markfunc listfunc feature months symbol)
  2122. "Subroutine of the function `diary-font-lock-keywords'.
  2123. If MARKFUNC is a member of `diary-nongregorian-marking-hook', or
  2124. LISTFUNC of `diary-nongregorian-listing-hook', then require FEATURE and
  2125. return a font-lock pattern matching array of MONTHS and marking SYMBOL."
  2126. `(when (or (memq ',markfunc diary-nongregorian-marking-hook)
  2127. (memq ',listfunc diary-nongregorian-listing-hook))
  2128. (require ',feature)
  2129. (diary-font-lock-date-forms ,months ,symbol)))
  2130. (defconst diary-time-regexp
  2131. ;; Accepted formats: 10:00 10.00 10h00 10h 10am 10:00am 10.00am
  2132. ;; Use of "." as a separator annoyingly matches numbers, eg "123.45".
  2133. ;; Hence often prefix this with "\\(^\\|\\s-\\)."
  2134. (concat "[0-9]?[0-9]\\([AaPp][mM]\\|\\("
  2135. "[Hh]\\([0-9][0-9]\\)?\\|[:.][0-9][0-9]"
  2136. "\\)\\([AaPp][Mm]\\)?\\)")
  2137. "Regular expression matching a time of day.")
  2138. (defvar calendar-hebrew-month-name-array-leap-year)
  2139. (defvar calendar-islamic-month-name-array)
  2140. (defvar calendar-bahai-month-name-array)
  2141. ;;;###cal-autoload
  2142. (defun diary-font-lock-keywords ()
  2143. "Return a value for the variable `diary-font-lock-keywords'."
  2144. (append
  2145. (diary-font-lock-date-forms calendar-month-name-array
  2146. nil calendar-month-abbrev-array)
  2147. (diary-font-lock-keywords-1 diary-hebrew-mark-entries
  2148. diary-hebrew-list-entries
  2149. cal-hebrew
  2150. calendar-hebrew-month-name-array-leap-year
  2151. diary-hebrew-entry-symbol)
  2152. (diary-font-lock-keywords-1 diary-islamic-mark-entries
  2153. diary-islamic-list-entries
  2154. cal-islam
  2155. calendar-islamic-month-name-array
  2156. diary-islamic-entry-symbol)
  2157. (diary-font-lock-keywords-1 diary-bahai-mark-entries
  2158. diary-bahai-list-entries
  2159. cal-bahai
  2160. calendar-bahai-month-name-array
  2161. diary-bahai-entry-symbol)
  2162. (list
  2163. (cons
  2164. (format "^%s.*$" (regexp-quote diary-include-string))
  2165. 'font-lock-keyword-face)
  2166. (cons
  2167. (format "^%s?\\(%s\\)" (regexp-quote diary-nonmarking-symbol)
  2168. (regexp-quote diary-sexp-entry-symbol))
  2169. '(1 font-lock-reference-face))
  2170. (cons
  2171. (format "^%s" (regexp-quote diary-nonmarking-symbol))
  2172. 'font-lock-reference-face)
  2173. (cons
  2174. (format "^%s?%s" (regexp-quote diary-nonmarking-symbol)
  2175. (regexp-opt (mapcar 'regexp-quote
  2176. (list diary-hebrew-entry-symbol
  2177. diary-islamic-entry-symbol
  2178. diary-bahai-entry-symbol))
  2179. t))
  2180. '(1 font-lock-reference-face))
  2181. '(diary-font-lock-sexps . font-lock-keyword-face)
  2182. ;; Don't need to worry about space around "-" because the first
  2183. ;; match takes care of that. It does mean the "-" itself may or
  2184. ;; may not be fontified though.
  2185. ;; diary-date-forms often include a final character that is not
  2186. ;; part of the date (eg a non-digit to mark the end of the year).
  2187. ;; This can use up the only space char between a date and time (b#7891).
  2188. ;; Hence we use OVERRIDE, which can only override whitespace.
  2189. ;; FIXME it's probably better to tighten up the diary-time-regexp
  2190. ;; and drop the whitespace requirement below.
  2191. `(,(format "\\(^\\|\\s-\\)%s\\(-%s\\)?" diary-time-regexp
  2192. diary-time-regexp)
  2193. . (0 'diary-time t)))))
  2194. ; . 'diary-time))))
  2195. (defvar diary-font-lock-keywords (diary-font-lock-keywords)
  2196. "Forms to highlight in `diary-mode'.")
  2197. ;;;###autoload
  2198. (define-derived-mode diary-mode fundamental-mode "Diary"
  2199. "Major mode for editing the diary file."
  2200. (set (make-local-variable 'font-lock-defaults)
  2201. '(diary-font-lock-keywords t))
  2202. (set (make-local-variable 'comment-start) diary-comment-start)
  2203. (set (make-local-variable 'comment-end) diary-comment-end)
  2204. (add-to-invisibility-spec '(diary . nil))
  2205. (add-hook 'after-save-hook 'diary-redraw-calendar nil t)
  2206. ;; In case the file was modified externally, refresh the calendar
  2207. ;; after refreshing the diary buffer.
  2208. (add-hook 'after-revert-hook 'diary-redraw-calendar nil t)
  2209. (if diary-header-line-flag
  2210. (setq header-line-format diary-header-line-format)))
  2211. ;;; Fancy Diary Mode.
  2212. (defun diary-fancy-date-pattern ()
  2213. "Return a regexp matching the first line of a fancy diary date header.
  2214. This depends on the calendar date style."
  2215. (concat
  2216. (let ((dayname (diary-name-pattern calendar-day-name-array nil t))
  2217. (monthname (diary-name-pattern calendar-month-name-array nil t))
  2218. (day "1")
  2219. (month "2")
  2220. ;; FIXME? This used to be "-?[0-9]+" - what was the "-?" for?
  2221. (year "3"))
  2222. ;; This is ugly. c-d-d-form expects `day' etc to be "numbers in
  2223. ;; string form"; eg the iso version calls string-to-number on some.
  2224. ;; Therefore we cannot eg just let day = "[0-9]+". (Bug#8583).
  2225. ;; Assumes no integers in c-day/month-name-array.
  2226. (replace-regexp-in-string "[0-9]+" "[0-9]+"
  2227. (mapconcat 'eval calendar-date-display-form "")
  2228. nil t))
  2229. ;; Optional ": holiday name" after the date.
  2230. "\\(: .*\\)?"))
  2231. (defun diary-fancy-date-matcher (limit)
  2232. "Search for a fancy diary data header, up to LIMIT."
  2233. ;; Any number of " other holiday name" lines, followed by "==" line.
  2234. (when (re-search-forward
  2235. (format "%s\\(\n +.*\\)*\n=+$" (diary-fancy-date-pattern)) limit t)
  2236. (put-text-property (match-beginning 0) (match-end 0) 'font-lock-multiline t)
  2237. t))
  2238. (define-obsolete-variable-alias 'fancy-diary-font-lock-keywords
  2239. 'diary-fancy-font-lock-keywords "23.1")
  2240. (defvar diary-fancy-font-lock-keywords
  2241. `((diary-fancy-date-matcher . diary-face)
  2242. ("^.*\\([aA]nniversary\\|[bB]irthday\\).*$" . 'diary-anniversary)
  2243. ("^.*Yahrzeit.*$" . font-lock-reference-face)
  2244. ("^\\(Erev \\)?Rosh Hodesh.*" . font-lock-function-name-face)
  2245. ("^Day.*omer.*$" . font-lock-builtin-face)
  2246. ("^Parashat.*$" . font-lock-comment-face)
  2247. (,(format "\\(^\\|\\s-\\)%s\\(-%s\\)?" diary-time-regexp
  2248. diary-time-regexp) . 'diary-time))
  2249. "Keywords to highlight in fancy diary display.")
  2250. ;; If region looks like it might start or end in the middle of a
  2251. ;; multiline pattern, extend the region to encompass the whole pattern.
  2252. (defun diary-fancy-font-lock-fontify-region-function (beg end &optional verbose)
  2253. "Function to use for `font-lock-fontify-region-function' in Fancy Diary.
  2254. Needed to handle multiline keyword in `diary-fancy-font-lock-keywords'.
  2255. Fontify the region between BEG and END, quietly unless VERBOSE is non-nil."
  2256. (goto-char beg)
  2257. (forward-line 0)
  2258. (if (looking-at "=+$") (forward-line -1))
  2259. (while (and (looking-at " +[^ ]")
  2260. (zerop (forward-line -1))))
  2261. ;; This check not essential.
  2262. (if (looking-at (diary-fancy-date-pattern))
  2263. (setq beg (line-beginning-position)))
  2264. (goto-char end)
  2265. (forward-line 0)
  2266. (while (and (looking-at " +[^ ]")
  2267. (zerop (forward-line 1))))
  2268. (if (looking-at "=+$")
  2269. (setq end (line-beginning-position 2)))
  2270. (font-lock-default-fontify-region beg end verbose))
  2271. (defvar diary-fancy-overriding-map (make-sparse-keymap)
  2272. "Keymap overriding minor-mode maps in `diary-fancy-display-mode'.")
  2273. (define-derived-mode diary-fancy-display-mode special-mode
  2274. "Diary"
  2275. "Major mode used while displaying diary entries using Fancy Display."
  2276. (set (make-local-variable 'font-lock-defaults)
  2277. '(diary-fancy-font-lock-keywords
  2278. t nil nil nil
  2279. (font-lock-fontify-region-function
  2280. . diary-fancy-font-lock-fontify-region-function)))
  2281. (set (make-local-variable 'minor-mode-overriding-map-alist)
  2282. (list (cons t diary-fancy-overriding-map)))
  2283. (view-mode 1))
  2284. (define-obsolete-function-alias 'fancy-diary-display-mode
  2285. 'diary-fancy-display-mode "23.1")
  2286. ;; Following code from Dave Love <fx@gnu.org>.
  2287. ;; Import Outlook-format appointments from mail messages in Gnus or
  2288. ;; Rmail using command `diary-from-outlook'. This, or the specialized
  2289. ;; functions `diary-from-outlook-gnus' and `diary-from-outlook-rmail',
  2290. ;; could be run from hooks to notice appointments automatically (in
  2291. ;; which case they will prompt about adding to the diary). The
  2292. ;; message formats recognized are customizable through `diary-outlook-formats'.
  2293. (defun diary-from-outlook-internal (subject body &optional test-only)
  2294. "Snarf a diary entry from a message assumed to be from MS Outlook.
  2295. SUBJECT and BODY are strings giving the message subject and body.
  2296. Arg TEST-ONLY non-nil means return non-nil if and only if the
  2297. message contains an appointment, don't make a diary entry."
  2298. (catch 'finished
  2299. (let (format-string)
  2300. (dolist (fmt diary-outlook-formats)
  2301. (when (eq 0 (string-match (car fmt) body))
  2302. (unless test-only
  2303. (setq format-string (cdr fmt))
  2304. (save-excursion
  2305. (save-window-excursion
  2306. (diary-make-entry
  2307. (format (replace-match (if (functionp format-string)
  2308. (funcall format-string body)
  2309. format-string)
  2310. t nil (match-string 0 body))
  2311. subject)))))
  2312. (throw 'finished t))))
  2313. nil))
  2314. (defvar gnus-article-mime-handles)
  2315. (defvar gnus-article-buffer)
  2316. (autoload 'gnus-fetch-field "gnus-util")
  2317. (autoload 'gnus-narrow-to-body "gnus")
  2318. (autoload 'mm-get-part "mm-decode")
  2319. (defun diary-from-outlook-gnus (&optional noconfirm)
  2320. "Maybe snarf diary entry from Outlook-generated message in Gnus.
  2321. Unless the optional argument NOCONFIRM is non-nil (which is the case when
  2322. this function is called interactively), then if an entry is found the
  2323. user is asked to confirm its addition.
  2324. Add this function to `gnus-article-prepare-hook' to notice appointments
  2325. automatically."
  2326. (interactive "p")
  2327. (with-current-buffer gnus-article-buffer
  2328. (let ((subject (gnus-fetch-field "subject"))
  2329. (body (if gnus-article-mime-handles
  2330. ;; We're multipart. Don't get confused by part
  2331. ;; buttons &c. Assume info is in first part.
  2332. (mm-get-part (nth 1 gnus-article-mime-handles))
  2333. (save-restriction
  2334. (gnus-narrow-to-body)
  2335. (buffer-string)))))
  2336. (when (diary-from-outlook-internal subject body t)
  2337. (when (or noconfirm (y-or-n-p "Snarf diary entry? "))
  2338. (diary-from-outlook-internal subject body)
  2339. (message "Diary entry added"))))))
  2340. (custom-add-option 'gnus-article-prepare-hook 'diary-from-outlook-gnus)
  2341. (defvar rmail-buffer)
  2342. (defun diary-from-outlook-rmail (&optional noconfirm)
  2343. "Maybe snarf diary entry from Outlook-generated message in Rmail.
  2344. Unless the optional argument NOCONFIRM is non-nil (which is the case when
  2345. this function is called interactively), then if an entry is found the
  2346. user is asked to confirm its addition."
  2347. (interactive "p")
  2348. ;; FIXME maybe the body needs rmail-mm decoding, in which case
  2349. ;; there is no single buffer with both body and subject, sigh.
  2350. (with-current-buffer rmail-buffer
  2351. (let ((subject (mail-fetch-field "subject"))
  2352. (body (buffer-substring (save-excursion
  2353. (rfc822-goto-eoh)
  2354. (point))
  2355. (point-max))))
  2356. (when (diary-from-outlook-internal subject body t)
  2357. (when (or noconfirm (y-or-n-p "Snarf diary entry? "))
  2358. (diary-from-outlook-internal subject body)
  2359. (message "Diary entry added"))))))
  2360. (defun diary-from-outlook (&optional noconfirm)
  2361. "Maybe snarf diary entry from current Outlook-generated message.
  2362. Currently knows about Gnus and Rmail modes. Unless the optional
  2363. argument NOCONFIRM is non-nil (which is the case when this
  2364. function is called interactively), then if an entry is found the
  2365. user is asked to confirm its addition."
  2366. (interactive "p")
  2367. (let ((func (cond
  2368. ((eq major-mode 'rmail-mode)
  2369. #'diary-from-outlook-rmail)
  2370. ((memq major-mode '(gnus-summary-mode gnus-article-mode))
  2371. #'diary-from-outlook-gnus)
  2372. (t (error "Don't know how to snarf in `%s'" major-mode)))))
  2373. (funcall func noconfirm)))
  2374. (provide 'diary-lib)
  2375. ;; Local Variables:
  2376. ;; coding: utf-8
  2377. ;; End:
  2378. ;;; diary-lib.el ends here