Sorting entries in emacs diary file - emacs

I use emacs diary.
As I append both future plans and daily review in the diary file,
the entries in the file results in not following chronological order.
When I review the diary file at some occasion, I would like to have these entries sorted.
Is there any commands or lisp that I can use to modify the diary file so that the entries get sorted in the chronological order?

A long time ago, I wrote myself a sort function:
(defun diary-sort-diary-keyfun nil
"Key function to order diary entries.
Entries sort in the groups: (days, anniversaries, cyclics, blocks, dates), with any unrecognised
forms before the groups.
Within each group, entries are in ascending date order.
You can prefix entries with `#' to comment them out without affecting sort order.
Prefixing with `&' also does not affect sort order."
(let ((number "\\s-+\\([0-9]+\\)")
(months '("Dec" "Nov" "Oct" "Sep" "Aug" "Jul" "Jun" "May" "Apr" "Mar" "Feb" "Jan"))
(days '("Saturday" "Friday" "Thursday" "Wednesday" "Tuesday" "Monday" "Sunday")))
(skip-chars-forward "#&")
(cond
((looking-at (concat "%%(diary-block" number number number number number number ")\\(.*\\)"))
(format "50%04d%02d%02d%04d%02d%02d%s"
(string-to-number (match-string 3))
(string-to-number (match-string 2)) (string-to-number (match-string 1))
(string-to-number (match-string 6))
(string-to-number (match-string 5)) (string-to-number (match-string 4))
(match-string 7)))
((looking-at (concat "%%(diary-cyclic" number number number number ")\\(.*\\)"))
(format "40%04d%02d%02d%05d%s"
(string-to-number (match-string 4))
(string-to-number (match-string 3)) (string-to-number (match-string 2))
(string-to-number (match-string 1))
(match-string 5)))
((looking-at (concat "%%(diary-anniversary" number number number ")\\(.*\\)"))
(format "30%04d%02d%02d%s"
(string-to-number (match-string 3))
(string-to-number (match-string 2)) (string-to-number (match-string 1))
(match-string 4)))
((looking-at "%%(\\(.*\\)") ; after all othe "%%()" rules
(format "20(%s" (match-string 1)))
((looking-at (concat "\\(" (mapconcat 'identity days "\\|") "\\)"
"\\( *[0-2 ][0-9]:[0-9][0-9]\\)?\\(.*\\)"))
(format "10%d%6s%s"
(length (member (match-string 1) days))
(or (match-string 2) "")
(match-string 3)))
((looking-at (concat "\\([0-9]+\\)\\s-+" "\\(" (mapconcat 'identity months "\\|") "\\)"
number "\\s-+\\([0-2 ][0-9]:[0-9][0-9]\\)?\\(.*\\)"))
(format "60%04d%02d%02d%6s%s"
(string-to-number (match-string 3))
(length (member (match-string 2) months))
(string-to-number (match-string 1))
(or (match-string 4) "")
(match-string 5)))
((looking-at (concat "\\(" (mapconcat 'identity months "\\|") "\\)"
number "," number "\\( *[0-2 ][0-9]:[0-9][0-9]\\)?\\(.*\\)"))
(format "60%04d%02d%02d%6s%s"
(string-to-number (match-string 3))
(length (member (match-string 1) months))
(string-to-number (match-string 2))
(or (match-string 4) "")
(match-string 5)))
((looking-at "[ \t\r]*$") ; blank line
(concat "99" (match-string 0)))
((looking-at ".*") ; last rule
(concat "00" (match-string 0))))))
(defun diary-sort-diary-file nil
"Sort the diary entries.
See `diary-sort-diary-keyfun' for the collation sequence."
(interactive "*")
;; sort-order:
;; randoms, days, anniversaries, cyclics, blocks, dates
(goto-char (point-min))
(let* ((locals-start (and (re-search-forward "\\(\n.*\\)Local variables:\\(.*\n\\)" nil t)
(match-beginning 0)))
(locals-end (and locals-start
(search-forward (concat (match-string 1) "End:" (match-string 2)) nil t)
(match-end 0)))
(locals (and locals-start locals-end
(buffer-substring-no-properties locals-start locals-end))))
(when locals
(delete-region locals-start locals-end))
(and (> (point-max) 1)
(/= (char-after (1- (point-max))) ?\n)
(goto-char (point-max))
(insert ?\n))
(goto-char (point-min))
(sort-subr nil 'forward-line 'end-of-line 'diary-sort-diary-keyfun)
(goto-char (point-max))
(insert "\n")
(delete-blank-lines)
(when locals
(insert locals))))
It's likely that I've assumed European date order, but if you prefer a different order, it shouldn't be hard to adapt it accordingly.
The way it works is that the keyfun returns a string that begins with two digits for the entry type (00 for unknowns, 10 for day-of-week entries, up to 60 for non-repeating dates), followed by a big-endian representation of the entry, like ISO 8601.
The interactive function, diary-sort-diary-file, then uses this keyfun. It saves any Local variables section, reinstating it at the end of the file (this is nice when you've inserted entries from calendar, as they get appended). If you have any LocalWords lines (for Ispell), then you could use similar code to keep that intact, or you could adapt the keyfun to place them last.
Sample results (somewhat censored):
&Sep 12 Xxxxxxx
&Monday 21:00 Xxxxxxx
#&Thursday Xxxxxxx
%%(diary-float t 0 2) Xxxxxxx
%%(diary-float t 6 1) Xxxxxxx
&%%(diary-phases-of-moon)
&%%(diary-anniversary 26 6 1952) Xxxxxxx
%%(diary-anniversary 1 6 1972) Xxxxxxx
&%%(diary-anniversary 15 3 1975) Xxxxxxx
&%%(diary-anniversary 7 2 1976) Xxxxxxx
%%(diary-anniversary 4 5 1977) International Star Wars day! :-)
&%%(diary-anniversary 13 8 1978) Xxxxxxx
&%%(diary-anniversary 26 8 1980) Xxxxxxx
&%%(diary-anniversary 16 10 1980) Xxxxxxx
&%%(diary-anniversary 15 3 2010) Xxxxxxx
&%%(diary-cyclic 1000 1 6 1972) Xxxxxxx
&%%(diary-cyclic 1000 13 8 1978) Xxxxxxx
&%%(diary-cyclic 1000 26 8 1980) Xxxxxxx
%%(diary-cyclic 1000 9 9 2013) Xxxxxxx
%%(diary-block 22 3 2013 24 3 2013) Xxxxxxx
%%(diary-block 6 4 2013 7 4 2013) Xxxxxxx
&%%(diary-block 20 4 2013 21 4 2013) Xxxxxxx
%%(diary-block 27 4 2013 28 4 2013) Xxxxxxx
%%(diary-block 18 5 2013 19 5 2013) Xxxxxxx
%%(diary-block 1 6 2013 2 6 2013) Xxxxxxx
%%(diary-block 1 6 2013 2 6 2013) Xxxxxxx
%%(diary-block 15 6 2013 16 6 2013) Xxxxxxx
%%(diary-block 22 6 2013 23 6 2013) Xxxxxxx
%%(diary-block 22 6 2013 30 6 2013) Xxxxxxx
%%(diary-block 6 7 2013 7 7 2013) Xxxxxxx
%%(diary-block 20 7 2013 24 7 2013) Xxxxxxx
%%(diary-block 9 8 2013 11 8 2013) Xxxxxxx
%%(diary-block 23 4 2016 24 4 2016) Xxxxxxx
%%(diary-block 13 8 2016 21 8 2016) Xxxxxxx
%%(diary-block 26 8 2016 28 8 2016) Xxxxxxx
22 Jun 2009 11:30 Xxxxxxx
30 Jun 2009 13:00 Xxxxxxx
&22 Jul 2009 Xxxxxxx
25 Jul 2009 Xxxxxxx
&14 Aug 2009 17:30 Xxxxxxx
&17 Aug 2009 Xxxxxxx
13 Mar 2010 Xxxxxxx
23 Mar 2010 10:50 Xxxxxxx
&17 Jan 2013 14:00 Xxxxxxx
1 Feb 2013 Xxxxxxx
&8 Feb 2013 16:00 Xxxxxxx
12 Feb 2013 18:30 Xxxxxxx
19 Feb 2013 18:00 Xxxxxxx
&12 Mar 2013 10:00 Xxxxxxx
16 Mar 2013 Xxxxxxx
&19 Mar 2013 13:50 Xxxxxxx
20 Mar 2016 Xxxxxxx
2 Apr 2016 Xxxxxxx
18 Jun 2016 Xxxxxxx
17 Jul 2016 Xxxxxxx
12 Nov 2016 Xxxxxxx
28 Mar 2017 Xxxxxxx
If you like to keep your diary file organised, you might also like these:
(define-generic-mode 'diary-generic-mode
'(?#)
nil ;; keywords
'(("^&.*$" (0 font-lock-comment-face))
("^&?\\(%%(diary-[a-z]+[^)]*)\\)" (1 font-lock-type-face t))
("^&?[ \t\n]*\\(\\([0-9*]+/[0-9*]+\\(/[0-9*]+\\)?\\|\\(Jan\\(uary\\)?\\|Feb\\(ruary\\)?\\|Mar\\(ch\\)?\\|Apr\\(il\\)?\\|May\\|June?\\|July?\\|Aug\\(ust\\)?\\|Sep\\(tember\\)?\\|Oct\\(ober\\)?\\|Nov\\(ember\\)?\\|Dec\\(ember\\)?\\|\\*\\)\\.?\\s-*[0-3]?[0-9]\\|\\(\\(Mon\\|Tues?\\|Wed\\(nes\\)?\\|Thu\\(rs\\)?\\|Fri\\|Sat\\(ur\\)?\\|Sun\\)\\(day\\)?\\)\\(\\s-[0-9]+\\)?\\)\\(,\\s-+\\(19\\|20\\)[0-9][0-9]\\)?\\s.?\\)" (1 font-lock-type-face t))
("^&?\\s-*\\([0-3]?[0-9]\\s-+\\(Jan\\(uary\\)?\\|Feb\\(ruary\\)?\\|Mar\\(ch\\)?\\|Apr\\(il\\)?\\|May\\|June?\\|July?\\|Aug\\(ust\\)?\\|Sep\\(tember\\)?\\|Oct\\(ober\\)?\\|Nov\\(ember\\)?\\|Dec\\(ember\\)?\\)\\s-+[0-9]+\\)" (1 font-lock-type-face t))
("[0-2]?[0-9]:[0-9][0-9]\\(am\\|pm\\)?\\>\\s.?" (0 font-lock-keyword-face t))) ;; font-lock
'("/diary") ;; auto-mode
'(diary-mode-setup) ;; function
"Mode for diary file.")
(defun diary-mode-setup nil
(set (make-local-variable 'align-rules-list)
'((date (regexp . "^&?\\([1-3]?[0-9]\\)\\(\\s-+\\)\\(+Jan\\|Feb\\|Ma[ry]\\|Apr\\|Ju[nl]\\|Aug\\|Sep\\|Oct\\|Nov\\|Dec\\)\\(\\s-+\\)[12][90-4][0-9][0-9]")
(group 2 4)
(justify . t))
(block (regexp . "^&?%%(diary-block\\(\\s-+[0-9]+\\)\\(\\s-+[0-9]+\\)\\(\\s-+[0-9]+\\)\\(\\s-+[0-9]+\\)\\(\\s-+[0-9]+\\)\\(\\s-+[0-9]+\\))")
(group 1 2 3 4 5 6)
(justify . t))
(cyclic (regexp . "^&?%%(diary-cyclic\\(\\s-+[0-9]+\\)\\(\\s-+[0-9]+\\)\\(\\s-+[0-9]+\\)\\(\\s-+[0-9]+\\))")
(group 1 2 3 4)
(justify . t))))
(set (make-local-variable 'require-final-newline) t)
(set (make-local-variable 'version-control) 'never))

In icalendar.el, function icalendar--datetime-to-iso-date, change format from "%d%s%d%s%d" to "%04d%s%02d%s%02d".
Add this to your initialization:
(setq
diary-date-forms diary-iso-date-forms
calendar-date-style 'iso
)
Edit old entries in your diary-file to the ISO standard, formatted as above, i.e YYYY/MM/DD. (The ISO standard is really YYYY-MM-DD).
Now further add this to your initialization:
(defun sort--diary (diary-filename)
(with-current-buffer
(set-buffer (find-file-noselect (expand-file-name diary-filename)))
(goto-char (point-min))
(while (search-forward "\C-j " nil t)
(replace-match "^j "))
(sort-lines nil (point-min) (point-max))
(goto-char (point-min))
(while (search-forward "^j" nil t)
(replace-match "\C-j"))
(save-buffer)))
(defvar sort--diary-filename (expand-file-name diary-file)
"History for sort--diary diary-filename")
(defun sort-diary (diary-filename)
"Sort diary file. Requires dates to use ISO standard"
(interactive (list (read-from-minibuffer
"diary file name: "
(car sort--diary-filename)
nil nil 'sort--diary-filename)))
(sort--diary diary-filename))
Now you can sort your diary by calling sort-diary.

Related

How to convert a list of numbers to separated strings using Lisp?

Given the following code:
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Copyright (C) 2014 Wojciech Siewierski ;;
;; ;;
;; This program is free software: you can redistribute it and/or modify ;;
;; it under the terms of the GNU General Public License as published by ;;
;; the Free Software Foundation, either version 3 of the License, or ;;
;; (at your option) any later version. ;;
;; ;;
;; This program is distributed in the hope that it will be useful, ;;
;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;;
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;;
;; GNU General Public License for more details. ;;
;; ;;
;; You should have received a copy of the GNU General Public License ;;
;; along with this program. If not, see <http://www.gnu.org/licenses/>. ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defvar *output*)
(defvar *indent*)
(defun format-tag (symbol &optional arg)
(cond
((equal arg 'begin)
(format nil "~{~a~}<~(~a~)" *indent* symbol))
((equal arg 'end)
(format nil "~{~a~}<~(/~a~)>~%" *indent* symbol))
(t
(format nil "~{~a~}~a~%" *indent* symbol))))
(defun sexp-to-xml--inside-tag (sexp)
(if sexp
(if (listp (car sexp))
(progn
(sexp-to-xml--new-tag (car sexp))
(sexp-to-xml--inside-tag (cdr sexp)))
(progn
(push (format-tag
(string (car sexp)))
*output*)
(sexp-to-xml--inside-tag (cdr sexp))))))
(defun sexp-to-xml--attrs (plist)
(when plist
(push (format nil " ~(~a~)=~s"
(car plist)
(cadr plist))
*output*)
(sexp-to-xml--attrs (cddr plist))))
(defun sexp-to-xml--new-tag (sexp)
(if (listp (car sexp))
(progn
(push (format-tag (caar sexp) 'begin)
*output*)
(sexp-to-xml--attrs (cdar sexp)))
(push (format-tag (car sexp) 'begin)
*output*))
(unless (cdr sexp)
(push (format nil " /")
*output*))
(push (format nil ">~%")
*output*)
(let ((*indent* (cons " " *indent*)))
(sexp-to-xml--inside-tag (cdr sexp)))
(when (cdr sexp)
(push (format-tag (if (listp (car sexp))
(caar sexp)
(car sexp))
'end)
*output*)))
(defun sexp-to-xml-unquoted (&rest sexps)
(apply #'concatenate 'string
(apply #'concatenate 'list
(loop for sexp in sexps collecting
(let ((*output* nil)
(*indent* nil))
(reverse (sexp-to-xml--new-tag sexp)))))))
(defmacro sexp-to-xml (&rest sexps)
`(format *standard-output* "~a"
(sexp-to-xml-unquoted ,#(loop for sexp in sexps collecting
`(quote ,sexp)))))
(defun file-get-contents (filename)
(with-open-file (stream filename)
(let ((contents (make-string (file-length stream))))
(read-sequence contents stream)
contents)))
(defun file-get-lines (filename)
(with-open-file (stream filename)
(loop for line = (read-line stream nil)
while line
collect line)))
(defun list-to-string (lst)
(format nil "~{~A~}" lst))
(defun test1()
(let((input (file-get-contents "sample2.sexp")))
(format t (sexp-to-xml-unquoted (read-from-string "(head (title \"my-site\"))")))
)
)
(defun test2()
(let((input (file-get-lines "sample2.sexp")))
(loop for sexp in input do (print (write-to-string sexp)))
)
)
(defun test3()
(let((input (file-get-lines "sample2.sexp")))
(format t (list-to-string input))
)
)
(defun :str->lst (str / i lst)
(repeat (setq i (strlen str))
(setq lst (cons (substr str (1+ (setq i (1- i))) 1) lst))))
(defun print-elements-recursively (list)
(when list ; do-again-test
(print (car list)) ; body
(print-elements-recursively ; recursive call
(cdr list)))) ; next-step-expression
(defun tokenize( str )(read-from-string (concatenate 'string "(" str
")")))
(defun test4()
(let((input (file-get-contents "sample2.sexp")))
(print-elements-recursively (tokenize input) )
)
)
(defun test5()
(let((input (file-get-contents "sample2.sexp")))
(print (sexp-to-xml-unquoted (tokenize input)))
)
)
(defun test6()
(let((input (file-get-contents "sample2.sexp")))
(loop for sexp in (tokenize input) do (
with-input-from-string (s (write-to-string sexp) )
(print ( sexp-to-xml-unquoted (read s)) )
)
)
)
)
(defun test7()
(let((input (file-get-contents "sample2.sexp")))
(loop for sexp in (tokenize input) do (
print sexp
)
)
)
)
(defun test8()
(let((input (file-get-contents "sample2.sexp")))
(format t (sexp-to-xml-unquoted (read-from-string input)))
)
)
I want to serialize into an xml file, specifically this sample file:
(supertux-tiles
(tilegroup
(name (_ "Snow"))
(tiles
7 8 9 202
13 14 15 204
10 11 12 206
16 17 18 205
30 31 114 113
21 22 19 203
20 23 207 208
3044 3045 3046 3047
3048 3049 3050 3051
3052 3053 3054 3055
3056 3057 3058 3059
2134 115 116 214
2135 117 118 1539
3249 3250 3251 3252
3253 3254 3255 3256
3261 3262 3263 3264
3265 3266 3267 3268
2121 2122 2123 0
2126 2127 2128 0
2131 2132 2133 0
2124 2125 0 0
2129 2130 0 0
2909 2910 2913 2914
2911 2912 2915 2916
1834 0 0 1835
2917 2918 2921 2922
2919 2920 2923 2924
0 1826 1827 0
1829 1830 1831 1832
1833 1834 1835 1836
3139 3140 3141 3142
3143 3144 3145 3146
0 3147 3148 0
3149 0 0 3150
3151 3152 3153 3154
3155 3156 3157 3158
0 1835 1834 0
1837 1838 1843 1844
1839 1840 1845 1846
1841 1842 1847 1848
0 0 1849 1850
2925 2926 2929 2930
0 2928 2931 0
0 0 2937 2940
2933 2935 2938 2941
2934 2936 2939 2942
2050 2051 2060 2061
2055 2056 2065 2066
2052 2053 2054 0
2057 2058 2059 0
2062 2063 2064 0
0 2067 2068 2069
0 2072 2073 2074
2075 2079 2076 2070
2077 2073 2078 2071
2178 3038 3039 3040
2406 3041 3042 3043
2155 2156 2157 2163
2158 2159 2154 2164
2160 2161 2162 2165
2166 2167 2168 2169
2170 2171 2172 2173
2174 2175 2176 2177
2384 2385 2386 2949
2387 2388 2389 2950
2390 2391 2392 2951
2393 2394 2395 2952
2953 2954 2955 2956
2957 2962 2398 2396
2958 2961 2399 2397
2959 2960 2997 2998
0 0 2963 2969
2975 2979 2964 2970
2976 2980 2965 2971
2977 2981 2966 2972
2978 2982 2967 2973
0 0 2968 2974
0 2986 2990 0
2983 2987 2991 2994
2984 2988 2992 2995
2985 2989 2993 2996
33 32 34 1741
35 37 39 1740
38 36 43 1739
40 41 42 1815
119 121 120 1816
)
)
)
But using test8 it gives an error:
7 is not a string designator.
Which led me to write a file like so:
(supertux-tiles
(tilegroup
(name (_ "Snow"))
(tiles
"7"
)
)
)
Which then compiles fine and the xml is generated upon, but I don't know how to convert all the integers into their string representation, reading from the list. I tried parsing the string and using the write-to-string method but I think I'm missing something.
Any help will be grated.
Thanks!
-- EDIT --
Changing string with princ-to-string as coredump suggested fixes the parsing evaluation of raw numbers within the string, however, when attempting to evaluate symbols such as t this is what it happens:
no dispatch function defined for #\T
using as an example the following
(tile
; dupe of tile 70, this one will be removed.
(id 63)
(deprecated #t)
(images
"tilesets/background/backgroundtile1.png"
)
)
It looks, though, that evaluating to a variable outside Lisp will be kept by only checking for the "t" xml tag.
This got solved.
A quick search on google lead to the following repository (https://github.com/Vifon/sexp-to-xml/blob/master/sexp-to-xml.lisp); the linked code is enough to reproduce the error. Note that when I run it from inside Emacs/Slime, the debugger shows the backtrace:
0: (STRING 7)
1: (SEXP-TO-XML--INSIDE-TAG (7 8 9 202 13 14 ...))
2: (SEXP-TO-XML--NEW-TAG (TILES 7 8 9 202 13 ...))
3: (SEXP-TO-XML--INSIDE-TAG ((TILES 7 8 9 202 13 ...)))
4: (SEXP-TO-XML--INSIDE-TAG ((NAME (_ "Snow")) (TILES 7 8 9 202 13 ...)))
5: (SEXP-TO-XML--NEW-TAG (TILEGROUP (NAME (_ "Snow")) (TILES 7 8 9 202 13 ...)))
6: (SEXP-TO-XML--INSIDE-TAG ((TILEGROUP (NAME #) (TILES 7 8 9 202 13 ...))))
7: (SEXP-TO-XML--NEW-TAG (SUPERTUX-TILES (TILEGROUP (NAME #) (TILES 7 8 9 202 13 ...))))
8: (SEXP-TO-XML-UNQUOTED (SUPERTUX-TILES (TILEGROUP (NAME #) (TILES 7 8 9 202 13 ...))))
Pressing v on various stack frames listed above, I can locate the places where the code currently is halted across the call stack.
I did not load a lisp file, but just evaluated the different forms in the current Emacs buffer, so there is no source file associated with functions. Yet, the AST form is stored for debugging purposes and the debugger can pinpoint where code execution currently is, wrapped in a fake (#:***HERE*** ...) form:
(SB-INT:NAMED-LAMBDA SEXP-TO-XML--INSIDE-TAG
(SEXP)
(BLOCK SEXP-TO-XML--INSIDE-TAG
(IF SEXP
(IF (LISTP (CAR SEXP))
(PROGN
(SEXP-TO-XML--NEW-TAG (CAR SEXP))
(SEXP-TO-XML--INSIDE-TAG (CDR SEXP)))
(PROGN
(PUSH (FORMAT-TAG (#:***HERE*** (STRING (CAR SEXP)))) *OUTPUT*)
(SEXP-TO-XML--INSIDE-TAG (CDR SEXP)))))))
Calling string on arbitrary values won't work, you need to replace that by princ-to-string in sexp-to-xml--inside-tag. Then it works as expected.

Clips: calculating age

I need a function for calculate age. I've just started to study CLIPS. I can calculate years but the answer is wrong.
(defrule calc-age
(person (date-of-birth ?dob))
=>
(bind ?age (- 2017 ?dob))
(printout t ?age))
CLIPS>
(deffunction age (?cy ; current year
?cm ; current month
?cd ; current day
?by ; birth year
?bm ; birth month
?bd) ; birth day
(bind ?age (- ?cy ?by))
(if (or (< ?cm ?bm)
(and (= ?cm ?bm) (< ?cd ?bd)))
then
(bind ?age (- ?age 1)))
?age)
CLIPS> (age 2017 4 6 2017 3 2)
0
CLIPS> (age 2017 4 6 2016 8 3)
0
CLIPS> (age 2017 4 6 2016 4 3)
1
CLIPS> (age 2017 4 6 2016 3 3)
1
CLIPS> (age 2017 4 6 2015 3 3)
2
CLIPS>

Algorithm to calculate the target-year of the target-month -- 12 month *Calendar*

GOAL:  The goal of this thread is to create a mathematical formula to replace the long-hand solution by #lawlist in the function lawlist-target-year-function (below).
NOTE:  The solution to this thread is somewhat similar, but will nevertheless be different, than the algorithm written by #AShelly in a related thread: https://stackoverflow.com/a/21709710/2112489
                                                                      STORY PROBLEM
There now exists a 12-month calendar in Emacs that scrolls forwards and backwards one month (or more) at a time. A helper function called lawlist-target-year-function is used by sevaral holiday functions to place an overlay on each holiday.
A full working draft of the 12-month scrolling calendar (including the long-hand solution) may be found here -- [the Github source code has been revised to include the concise algorithm solution by #legoscia]:
             https://github.com/lawlist/calendar-yearly-scroll-by-month/blob/master/lawlist-cal.el
LEGEND:
displayed-month (numbers 1 through 12) is the month that appears in the upper left-hand corner of the buffer, and this changes as the 12-month calendar is scrolled forwards or backwards.
The target-month (numbers 1 through 12) is the month that contains the holiday that will be marked with an overlay. There are three (3) possible x axis coordinates (i.e., column 1, column 2, or column 3). There are four (4) possible y axis coordinates (i.e., row 1, row 2, row 3, or row 4). [Citation to x / y coordinates: http://www.mathsisfun.com/data/cartesian-coordinates.html ]
The displayed-year is the year that appears in the upper left-hand corner of the buffer, and this changes as the 12-month calendar is scrolled forwards or backwards.
The target year is the year of the target-month.
EXAMPLE:
When displayed-month is January (i.e., 1), then the year is the same for all target months.
When displayed-month is February (i.e., 2):
(if (memq target-month `(2 3 4 5 6 7 8 9 10 11 12))
displayed-year
(+ displayed-year 1))
When displayed-month is March (i.e., 3):
(if (memq target-month `(3 4 5 6 7 8 9 10 11 12))
displayed-year
(+ displayed-year 1))
When displayed-month is April (i.e., 4):
(if (memq target-month `(4 5 6 7 8 9 10 11 12))
displayed-year
(+ displayed-year 1))
When displayed-month is May (i.e., 5)
(if (memq target-month `(5 6 7 8 9 10 11 12))
displayed-year
(+ displayed-year 1))
When displayed-month is June (i.e., 6):
(if (memq target-month `(6 7 8 9 10 11 12))
displayed-year
(+ displayed-year 1))
When displayed-month is July (i.e., 7):
(if (memq target-month `(7 8 9 10 11 12))
displayed-year
(+ displayed-year 1))
When displayed-month is August (i.e, 8):
(if (memq target-month `(8 9 10 11 12))
displayed-year
(+ displayed-year 1))
When displayed-month is September (i.e., 9):
(if (memq target-month `(9 10 11 12))
displayed-year
(+ displayed-year 1))
When displayed-month is October (i.e., 10):
(if (memq target-month `(10 11 12))
displayed-year
(+ displayed-year 1))
When displayed-month is November (i.e., 11):
(if (memq target-month `(11 12))
displayed-year
(+ displayed-year 1))
When displayed-month is December (i.e., 12):
(if (memq target-month `(12))
displayed-year
(+ displayed-year 1))
The 12-month calendar looks like the following as the layout scrolls forward one month at a time:
;; 1 2 3
;; 4 5 6
;; 7 8 9
;; 10 11 12
;; 2 3 4
;; 5 6 7
;; 8 9 10
;; 11 12 1
;; 3 4 5
;; 6 7 8
;; 9 10 11
;; 12 1 2
;; 4 5 6
;; 7 8 9
;; 10 11 12
;; 1 2 3
;; 5 6 7
;; 8 9 10
;; 11 12 1
;; 2 3 4
;; 6 7 8
;; 9 10 11
;; 12 1 2
;; 3 4 5
;; 7 8 9
;; 10 11 12
;; 1 2 3
;; 4 5 6
;; 8 9 10
;; 11 12 1
;; 2 3 4
;; 5 6 7
;; 9 10 11
;; 12 1 2
;; 3 4 5
;; 6 7 8
;; 10 11 12
;; 1 2 3
;; 4 5 6
;; 7 8 9
;; 11 12 1
;; 2 3 4
;; 5 6 7
;; 8 9 10
;; 12 1 2
;; 3 4 5
;; 6 7 8
;; 9 10 11
The long-hand solution by #lawlist is as follows:
(defun lawlist-target-year-function (target-month)
(cond
;; 1 2 3
;; 4 5 6
;; 7 8 9
;; 10 11 12
((eq displayed-month 1)
displayed-year)
;; 2 3 4
;; 5 6 7
;; 8 9 10
;; 11 12 1
((eq displayed-month 2)
(if (memq target-month `(2 3 4 5 6 7 8 9 10 11 12))
displayed-year
(+ displayed-year 1)))
;; 3 4 5
;; 6 7 8
;; 9 10 11
;; 12 1 2
((eq displayed-month 3)
(if (memq target-month `(3 4 5 6 7 8 9 10 11 12))
displayed-year
(+ displayed-year 1)))
;; 4 5 6
;; 7 8 9
;; 10 11 12
;; 1 2 3
((eq displayed-month 4)
(if (memq target-month `(4 5 6 7 8 9 10 11 12))
displayed-year
(+ displayed-year 1)))
;; 5 6 7
;; 8 9 10
;; 11 12 1
;; 2 3 4
((eq displayed-month 5)
(if (memq target-month `(5 6 7 8 9 10 11 12))
displayed-year
(+ displayed-year 1)))
;; 6 7 8
;; 9 10 11
;; 12 1 2
;; 3 4 5
((eq displayed-month 6)
(if (memq target-month `(6 7 8 9 10 11 12))
displayed-year
(+ displayed-year 1)))
;; 7 8 9
;; 10 11 12
;; 1 2 3
;; 4 5 6
((eq displayed-month 7)
(if (memq target-month `(7 8 9 10 11 12))
displayed-year
(+ displayed-year 1)))
;; 8 9 10
;; 11 12 1
;; 2 3 4
;; 5 6 7
((eq displayed-month 8)
(if (memq target-month `(8 9 10 11 12))
displayed-year
(+ displayed-year 1)))
;; 9 10 11
;; 12 1 2
;; 3 4 5
;; 6 7 8
((eq displayed-month 9)
(if (memq target-month `(9 10 11 12))
displayed-year
(+ displayed-year 1)))
;; 10 11 12
;; 1 2 3
;; 4 5 6
;; 7 8 9
((eq displayed-month 10)
(if (memq target-month `(10 11 12))
displayed-year
(+ displayed-year 1)))
;; 11 12 1
;; 2 3 4
;; 5 6 7
;; 8 9 10
((eq displayed-month 11)
(if (memq target-month `(11 12))
displayed-year
(+ displayed-year 1)))
;; 12 1 2
;; 3 4 5
;; 6 7 8
;; 9 10 11
((eq displayed-month 12)
(if (memq target-month `(12))
displayed-year
(+ displayed-year 1))) ))
Would this work?
(defun lawlist-target-year-function (target-month)
(if (>= target-month displayed-month)
displayed-year
(1+ displayed-year)))

Algorithms for moving the cursor to a date on a 12 month rotating calendar in Emacs

GOAL:  The goal of this thread is to create two (2) mathematical formulas to replace the long-hand solution by #lawlist in the function lawlist-calendar-cursor-to-visible-date (below).
                                                            STORY PROBLEM
There now exists a 12-month calendar in Emacs that scrolls forwards and backwards one month (or more) at a time. The function lawlist-calendar-cursor-to-visible-date is used to mark dates with overlays for designated events (e.g., birthdays, holidays, appointments, etc.); or, to simply move the cursor to a particular date. #lawlist has devised a solution by long-hand, which does not entirely use mathematical equations to calculate the cursor position for each of the 365 days that are displayed. It may be possible to create two (2) concise algorithms to replace the long-hand solution.
A working draft of the 12-month scrolling calendar (without the long-hand solution) may be found here:
     https://stackoverflow.com/a/21409154/2112489
LEGEND:
displayed-month (numbers 1 through 12) is the month that appears in the upper left-hand corner of the buffer, and this changes as the 12-month calendar is scrolled forwards or backwards.
The target month (numbers 1 through 12) is the month that we need to locate with assistance from the two mathematical formulas -- its location varies depending upon the date being marked (e.g., birthday, holiday, appointment), and depending upon the displayed-month in the upper left-hand corner of the buffer. The target month can be in any one of 12 possible positions. There are three (3) possible x axis coordinates (i.e., 6, 31, or 56). There are four (4) possible y axis coordinates (i.e., 0, 9, 18 or 27). [Citation to x / y coordinates: http://www.mathsisfun.com/data/cartesian-coordinates.html ]
A row is defined as 3 months horizontally.
A column is defined as 4 months vertically.
The first forumula must equal 0, 9, 18 or 27 depending upon whether the point is on row 1, 2, 3 or 4 -- i.e., from top to bottom.
The second forumula must equal 6, 31, or 56 depending upon whether the point is on column 1, 2 or 3 -- i.e., from left to right.
EXAMPLE:
If displayed-month is January (i.e., 1) and the target month is August (i.e., 8), then row equals 18 and column equals 31.
If displayed-month is February (i.e., 2) and the target month is August (i.e., 8), then row equals 18 and column equals 6.
If displayed-month is March (i.e., 3) and the target month is August (i.e., 8), then row equals 9 and column equals 56.
If displayed-month is April (i.e., 4) and target month is August (i.e., 8), then row equals 9 and column equals 31.
If displayed-month is May (i.e., 5) and the target month is August (i.e., 8), then row equals 9 and column equals 6.
The 12-month calendar looks like the following as the layout scrolls forward one month at a time:
;; 1 2 3
;; 4 5 6
;; 7 8 9
;; 10 11 12
;; 2 3 4
;; 5 6 7
;; 8 9 10
;; 11 12 1
;; 3 4 5
;; 6 7 8
;; 9 10 11
;; 12 1 2
;; 4 5 6
;; 7 8 9
;; 10 11 12
;; 1 2 3
;; 5 6 7
;; 8 9 10
;; 11 12 1
;; 2 3 4
;; 6 7 8
;; 9 10 11
;; 12 1 2
;; 3 4 5
;; 7 8 9
;; 10 11 12
;; 1 2 3
;; 4 5 6
;; 8 9 10
;; 11 12 1
;; 2 3 4
;; 5 6 7
;; 9 10 11
;; 12 1 2
;; 3 4 5
;; 6 7 8
;; 10 11 12
;; 1 2 3
;; 4 5 6
;; 7 8 9
;; 11 12 1
;; 2 3 4
;; 5 6 7
;; 8 9 10
;; 12 1 2
;; 3 4 5
;; 6 7 8
;; 9 10 11
The long-hand solution by #lawlist is as follows:
(defun lawlist-calendar-cursor-to-visible-date (date)
"Move the cursor to DATE that is on the screen."
(let* (
(month (calendar-extract-month date))
(day (calendar-extract-day date))
(year (calendar-extract-year date))
(first-of-month-weekday (calendar-day-of-week (list month 1 year))))
(goto-line
(+ 3
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(cond
;; 1 2 3
;; 4 5 6
;; 7 8 9
;; 10 11 12
((and
(eq displayed-month 1)
(memq month `(1 2 3)))
0)
((and
(eq displayed-month 1)
(memq month `(4 5 6)))
9)
((and
(eq displayed-month 1)
(memq month `(7 8 9)))
18)
((and
(eq displayed-month 1)
(memq month `(10 11 12)))
27)
;; 2 3 4
;; 5 6 7
;; 8 9 10
;; 11 12 1
((and
(eq displayed-month 2)
(memq month `(2 3 4)))
0)
((and
(eq displayed-month 2)
(memq month `(5 6 7)))
9)
((and
(eq displayed-month 2)
(memq month `(8 9 10)))
18)
((and
(eq displayed-month 2)
(memq month `(11 12 1)))
27)
;; 3 4 5
;; 6 7 8
;; 9 10 11
;; 12 1 2
((and
(eq displayed-month 3)
(memq month `(3 4 5)))
0)
((and
(eq displayed-month 3)
(memq month `(6 7 8)))
9)
((and
(eq displayed-month 3)
(memq month `(9 10 11)))
18)
((and
(eq displayed-month 3)
(memq month `(12 1 2)))
27)
;; 4 5 6
;; 7 8 9
;; 10 11 12
;; 1 2 3
((and
(eq displayed-month 4)
(memq month `(4 5 6)))
0)
((and
(eq displayed-month 4)
(memq month `(7 8 9)))
9)
((and
(eq displayed-month 4)
(memq month `(10 11 12)))
18)
((and
(eq displayed-month 4)
(memq month `(1 2 3)))
27)
;; 5 6 7
;; 8 9 10
;; 11 12 1
;; 2 3 4
((and
(eq displayed-month 5)
(memq month `(5 6 7)))
0)
((and
(eq displayed-month 5)
(memq month `(8 9 10)))
9)
((and
(eq displayed-month 5)
(memq month `(11 12 1)))
18)
((and
(eq displayed-month 5)
(memq month `(2 3 4)))
27)
;; 6 7 8
;; 9 10 11
;; 12 1 2
;; 3 4 5
((and
(eq displayed-month 6)
(memq month `(6 7 8)))
0)
((and
(eq displayed-month 6)
(memq month `(9 10 11)))
9)
((and
(eq displayed-month 6)
(memq month `(12 1 2)))
18)
((and
(eq displayed-month 6)
(memq month `(3 4 5)))
27)
;; 7 8 9
;; 10 11 12
;; 1 2 3
;; 4 5 6
((and
(eq displayed-month 7)
(memq month `(7 8 9)))
0)
((and
(eq displayed-month 7)
(memq month `(10 11 12)))
9)
((and
(eq displayed-month 7)
(memq month `(1 2 3)))
18)
((and
(eq displayed-month 7)
(memq month `(4 5 6)))
27)
;; 8 9 10
;; 11 12 1
;; 2 3 4
;; 5 6 7
((and
(eq displayed-month 8)
(memq month `(8 9 10)))
0)
((and
(eq displayed-month 8)
(memq month `(11 12 1)))
9)
((and
(eq displayed-month 8)
(memq month `(2 3 4)))
18)
((and
(eq displayed-month 8)
(memq month `(5 6 7)))
27)
;; 9 10 11
;; 12 1 2
;; 3 4 5
;; 6 7 8
((and
(eq displayed-month 9)
(memq month `(9 10 11)))
0)
((and
(eq displayed-month 9)
(memq month `(12 1 2)))
9)
((and
(eq displayed-month 9)
(memq month `(3 4 5)))
18)
((and
(eq displayed-month 9)
(memq month `(6 7 8)))
27)
;; 10 11 12
;; 1 2 3
;; 4 5 6
;; 7 8 9
((and
(eq displayed-month 10)
(memq month `(10 11 12)))
0)
((and
(eq displayed-month 10)
(memq month `(1 2 3)))
9)
((and
(eq displayed-month 10)
(memq month `(4 5 6)))
18)
((and
(eq displayed-month 10)
(memq month `(7 8 9)))
27)
;; 11 12 1
;; 2 3 4
;; 5 6 7
;; 8 9 10
((and
(eq displayed-month 11)
(memq month `(11 12 1)))
0)
((and
(eq displayed-month 11)
(memq month `(2 3 4)))
9)
((and
(eq displayed-month 11)
(memq month `(5 6 7)))
18)
((and
(eq displayed-month 11)
(memq month `(8 9 10)))
27)
;; 12 1 2
;; 3 4 5
;; 6 7 8
;; 9 10 11
((and
(eq displayed-month 12)
(memq month `(12 1 2)))
0)
((and
(eq displayed-month 12)
(memq month `(3 4 5)))
9)
((and
(eq displayed-month 12)
(memq month `(6 7 8)))
18)
((and
(eq displayed-month 12)
(memq month `(9 10 11)))
27) )
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(/ (+ day -1
(mod
(- (calendar-day-of-week (list month 1 year)) calendar-week-start-day)
7))
7)))
(move-to-column
(+
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(cond
;; 1 2 3
;; 4 5 6
;; 7 8 9
;; 10 11 12
((and
(eq displayed-month 1)
(memq month `(1 4 7 10)))
6)
((and
(eq displayed-month 1)
(memq month `(2 5 8 11)))
31)
((and
(eq displayed-month 1)
(memq month `(3 6 9 12)))
56)
;; 2 3 4
;; 5 6 7
;; 8 9 10
;; 11 12 1
((and
(eq displayed-month 2)
(memq month `(2 5 8 11)))
6)
((and
(eq displayed-month 2)
(memq month `(3 6 9 12)))
31)
((and
(eq displayed-month 2)
(memq month `(4 7 10 1)))
56)
;; 3 4 5
;; 6 7 8
;; 9 10 11
;; 12 1 2
((and
(eq displayed-month 3)
(memq month `(3 6 9 12)))
6)
((and
(eq displayed-month 3)
(memq month `(4 7 10 1)))
31)
((and
(eq displayed-month 3)
(memq month `(5 8 11 2)))
56)
;; 4 5 6
;; 7 8 9
;; 10 11 12
;; 1 2 3
((and
(eq displayed-month 4)
(memq month `(4 7 10 1)))
6)
((and
(eq displayed-month 4)
(memq month `(5 8 11 2)))
31)
((and
(eq displayed-month 4)
(memq month `(6 9 12 3)))
56)
;; 5 6 7
;; 8 9 10
;; 11 12 1
;; 2 3 4
((and
(eq displayed-month 5)
(memq month `(5 8 11 2)))
6)
((and
(eq displayed-month 5)
(memq month `(6 9 12 3)))
31)
((and
(eq displayed-month 5)
(memq month `(7 10 1 4)))
56)
;; 6 7 8
;; 9 10 11
;; 12 1 2
;; 3 4 5
((and
(eq displayed-month 6)
(memq month `(6 9 12 3)))
6)
((and
(eq displayed-month 6)
(memq month `(7 10 1 4)))
31)
((and
(eq displayed-month 6)
(memq month `(8 11 2 5)))
56)
;; 7 8 9
;; 10 11 12
;; 1 2 3
;; 4 5 6
((and
(eq displayed-month 7)
(memq month `(7 10 1 4)))
6)
((and
(eq displayed-month 7)
(memq month `(8 11 2 5)))
31)
((and
(eq displayed-month 7)
(memq month `(9 12 3 6)))
56)
;; 8 9 10
;; 11 12 1
;; 2 3 4
;; 5 6 7
((and
(eq displayed-month 8)
(memq month `(8 11 2 5)))
6)
((and
(eq displayed-month 8)
(memq month `(9 12 3 6)))
31)
((and
(eq displayed-month 8)
(memq month `(10 1 4 7)))
56)
;; 9 10 11
;; 12 1 2
;; 3 4 5
;; 6 7 8
((and
(eq displayed-month 9)
(memq month `(9 12 3 6)))
6)
((and
(eq displayed-month 9)
(memq month `(10 1 4 7)))
31)
((and
(eq displayed-month 9)
(memq month `(11 2 5 8)))
56)
;; 10 11 12
;; 1 2 3
;; 4 5 6
;; 7 8 9
((and
(eq displayed-month 10)
(memq month `(10 1 4 7)))
6)
((and
(eq displayed-month 10)
(memq month `(11 2 5 8)))
31)
((and
(eq displayed-month 10)
(memq month `(12 3 6 9)))
56)
;; 11 12 1
;; 2 3 4
;; 5 6 7
;; 8 9 10
((and
(eq displayed-month 11)
(memq month `(11 2 5 8)))
6)
((and
(eq displayed-month 11)
(memq month `(12 3 6 9)))
31)
((and
(eq displayed-month 11)
(memq month `(1 4 7 10)))
56)
;; 12 1 2
;; 3 4 5
;; 6 7 8
;; 9 10 11
((and
(eq displayed-month 12)
(memq month `(12 3 6 9)))
6)
((and
(eq displayed-month 12)
(memq month `(1 4 7 10)))
31)
((and
(eq displayed-month 12)
(memq month `(2 5 8 11)))
56) )
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(* 3 (mod
(- (calendar-day-of-week date) calendar-week-start-day)
7))))))
I must be missing something because it looks like the formulas are as simple as (pseudocode):
first = 9 * ( rows - 1 )
second = 6 + 25 * ( cols - 1 )
based on your edit, you can calculate the rows and cols to move with:
if target > display
difference = target - display
else
difference = 12 + target - display
rows = difference / 3
cols = difference % 3
rowmove = 9 * rows
colmove = 6 + 25 * cols
And then use the formula above.
My attempt at elisp:
(let difference (if (>= target-month display-month)
(- target-month display-month)
(- (+ target-month 12) display-month)))
(let rows (/ difference 3))
(let cols (% difference 3))
(let rowmove (* 9 rows))
(let colmove (+ 6 (* 25 cols)))

How to print a list as matrix in Common Lisp

I am working in Common Lisp, trying to make Windows game minesweeper.
I have a list (1 1 1 2 2 2 3 3 3) and want to print that like matrix
(1 1 1
2 2 2
3 3 3)
How to do that?
Edit
I am at the beginning of
(format t "Input width:")
(setf width (read))
(format t "Input height:")
(setf height (read))
(format t "How many mines:")
(setf brMina (read))
(defun matrica (i j)
(cond ((= 0 i) '())
(t (append (vrsta j) (matrica (1- i) j) ))))
(setf minefield (matrica width height))
(defun stampaj ()
(format t "~%~a" minefield ))
Another example, using the pretty-printer for fun:
(defun print-list-as-matrix
(list elements-per-row
&optional (cell-width (1+ (truncate (log (apply #'max list) 10)))))
(let ((*print-right-margin* (* elements-per-row (1+ cell-width)))
(*print-miser-width* nil)
(*print-pretty* t)
(format-string (format nil "~~<~~#{~~~ad~~^ ~~}~~#:>~%" cell-width)))
(format t format-string list)))
Works like this:
CL-USER> (print-list-as-matrix (loop for i from 1 to 9 collect i) 3)
1 2 3
4 5 6
7 8 9
NIL
CL-USER> (print-list-as-matrix (loop for i from 1 to 25 collect i) 5)
1 2 3 4 5
6 7 8 9 10
11 12 13 14 15
16 17 18 19 20
21 22 23 24 25
NIL
CL-USER> (print-list-as-matrix (loop for i from 1 to 16 collect i) 2)
1 2
3 4
5 6
7 8
9 10
11 12
13 14
15 16
Like this:
(defun print-list-as-grid (list rows cols)
(assert (= (length list) (* rows cols))
(loop for row from 0 below rows do
(loop for col from 0 below cols do
(princ (car list))
(princ #\space)
(setf list (cdr list)))
(princ #\newline)))
* (print-list-as-grid '(a b c d e f g h i) 3 3)
A B C
D E F
G H I
NIL