How do I hard-code arguments in emacs lisp? - emacs

I have the following function in my .emacs that notifies me after I've worked for a suitable amount of time.
Problem is, I'm unable to hardcode the values time and msg, so I have to reenter them each time.
(defun timed-notification(time msg)
(interactive "sNotification when (e.g: 2 minutes, 60 seconds, 3 days): \nsMessage: ")
(run-at-time time
nil
(lambda (msg) (terminal-notifier-notify "Pomodoro" msg))
msg))
(setq column-number-mode t)
How do I set the time to always be "25 min" and the message to be "Take a break, time's up!"?
Here is my attempt:
(defun timed-notification()
;(interactive "sNotification when (e.g: 2 minutes, 60 seconds, 3 days): \nsMessage: ")
(run-at-time 25
nil
(lambda ("Time's up")
(terminal-notifier-notify "Take a break, time's up!" msg))
msg))
(setq column-number-mode t)

Define your function like you did originally, then invoke it once with the parameters you want. The interactive form, like its name suggests, is only used when you actually invoke the function interactively. When you invoke it from code, you pass the parameters; so the interactive form is simply ignored.
(defun timed-notification (time msg)
(interactive "sNotification when (e.g: 2 minutes, 60 seconds, 3 days): \nsMessage: ")
(run-at-time time nil (lambda (msg) (terminal-notifier-notify "Pomodoro" msg)) msg))
(setq column-number-mode t)
(timed-notification 25 "Take a break, time's up!") ;; New addition

You got rid of the msg parameter, but you were still trying to use it. Use let to bind a local variable to that value.
(defun timed-notification()
(interactive)
(let ((msg "Take a break, time's up!"))
(run-at-time 25 nil (lambda (mess) (terminal-notifier-notify "pomodoro" mess)) msg)))

(defun timed-notification (time msg)
(interactive "sNotification when (e.g: 2 minutes, 60 seconds, 3 days): \nsMessage: ")
(run-at-time time nil (lambda (msg) (terminal-notifier-notify "Pomodoro" msg)) msg))
(setq column-number-mode t)
(defun tf()
(interactive)
(timed-notification "1 min" "Take a break, time's up!"))
Now tf can be called for a regular pomo, while the original function is still available for when I want an x-minute break.

Related

using date-time in emacs spreadsheets

I'm just starting to use ses-mode in emacs, and I plan to use it with timestamps, but I do not manage to have them parsed in a way that I can then use.
I'm taking measurements on three days of the week, so my distances between one measurement and the other is either 2 or 3 days. I chose to use ses-mode in emacs because it runs on all of my computers, including the phone.
my spreadsheet contains datestamp, conductivity, temperature, and gallon count, a couple of subsequent lines would look like this:
2014-10-03 2.95 33.4 4031070
2014-10-06 3.07 33.5 4086930
2014-10-08 2.97 33.6 4119590
I would add two more columns, the first with the difference of days between the readings, the second with the "gallon-per-day" value.
I do not manage to have the string timestamp parsed into a format where I can do computations, staying within a simple emacs spreadsheet (SES).
I've tried date-to-time, but it always returns the same value (14445 17280).
parse-time-string gives me a 9-tuple which I can't directly pass to format-time-string.
The function encode-time helps:
(let ((l (parse-time-string "2014-09-12")))
(format-time-string "%d %m %Y" (encode-time 0 0 0 (nth 3 l) (nth 4 l) (nth 5 l))))
The following version uses cl-flet to avoid doubling of code if the encoding is needed multiple times. If you need the encoding also in other functions you can use defun instead of cl-flet.
(eval-when (compile) (require 'cl)) ;; for cl-flet
(let ((A2 "2014-10-08") ;; just for testing
(A1 "2014-10-03")) ;; just for testing
(cl-flet ((encode (str)
(let ((l (parse-time-string str)))
(encode-time 0 0 0 (nth 3 l) (nth 4 l) (nth 5 l)))))
(let* ((t-prev (encode A1))
(t-this (encode A2)))
(/ (time-to-seconds (time-subtract t-this t-prev)) (* 24 60 60)))))
As a function:
(eval-when (compile) (require 'cl)) ;; for cl-flet
(defun day-diff (date1 date2)
"Calculate the difference of dates in days between DATE1-STR and DATE2-STR."
(interactive "sDate1:\nsDate2:")
(cl-flet ((encode (str)
(let ((l (parse-time-string str)))
(encode-time 0 0 0 (nth 3 l) (nth 4 l) (nth 5 l)))))
(setq date1 (encode date1)
date2 (encode date2))
(let ((ret (/ (time-to-seconds (time-subtract date1 date2)) (* 24 60 60))))
(when (called-interactively-p 'any)
(message "Day difference: %s" ret))
ret)))
(put 'day-diff 'safe-function t)
An alternative using calc would be:
(require 'calc)
(defun day-diff (date1 date2)
"Calculate the difference of dates in days between DATE1-STR and DATE2-STR."
(interactive "sDate1:\nsDate2:")
(let ((ret (string-to-number (calc-eval (format "<%s>-<%s>" date1 date2)))))
(when (called-interactively-p 'any)
(message "Day difference: %s" ret))
ret))
If you omit the nice-to-have features this becomes almost a simple cell formula: (string-to-number (calc-eval (format "<%s>-<%s>" A1 A2))).
If you want to save the stuff in the spreadsheet you can put the defun in table cell A1. A more simple example:
(progn (defun day-diff (date1 date2) (string-to-number (calc-eval (format "<%s>-<%s>" date1 date2)))) (put 'day 'safe-function t) "Actual header")
To have a more convenient editing possibility you can switch to M-x lisp-mode.
There you find
^L
(ses-cell A1 "Actual Header" (progn (defun day-diff (date1 date2) (string-to-number (calc-eval (format "<%s>-<%s>" date1 date2)))) (put 'day 'safe-function t) "Actual header") nil nil)
which you can edit. But do not insert linebreaks! ses identifies cell-positions with line numbers in that file!
Another nice alternative is to put the definition of your function into the file-local variable list.
Switch to lisp-interaction mode by M-x lisp-interaction-mode.
Go to the end of the file. There you find the lines:
;; Local Variables:
;; mode: ses
;; End:
Add your function definition as eval to this list:
;; Local Variables:
;; mode: ses
;; eval:
;; (progn
;; (defun day-diff (date1 date2)
;; (string-to-number (calc-eval (format "<%s>-<%s>" date1 date2))))
;; (put 'day-diff 'safe-function t))
;; End:
You can add the progn without the comment characters ;. In this case even indentation works. Afterwards you can call comment-region for the progn.
You can save the file and run M-x normal-mode. Afterwards the function is defined and you can use it in the spreadsheet.

org-deadline -- change all in selected block in one fell swoop

Could someone please steer me in the right direction towards automating this function so that I only type the date one time (or select it with the mouse from the built-in popup calendar) and hit the return key, and then it repeats the process all by itself until finished.
(setq org-loop-over-headlines-in-active-region t)
(defun change-all-deadlines ()
"Change all deadlines in the group of tasks that are selected / highlighted."
(interactive)
(org-deadline)
(org-map-entries)
(let (new-date
(minibuffer-message "Please insert the new date, and then press RET to continue.")
[User enters (with choice to use built-in calendar popup): July 5, 2013]
(format "%s" (new-date))
[Then magic happens automatically -- :)]
(minibuffer-message "Congratulations -- all dates have been changed to %s." new-date))))
EDIT: Here is the main function from .../lisp/org.el
(defun org-deadline (&optional remove time)
"Insert the \"DEADLINE:\" string with a timestamp to make a deadline.
With argument REMOVE, remove any deadline from the item.
With argument TIME, set the deadline at the corresponding date. TIME
can either be an Org date like \"2011-07-24\" or a delta like \"+2d\"."
(interactive "P")
(if (and (org-region-active-p) org-loop-over-headlines-in-active-region)
(let ((cl (if (eq org-loop-over-headlines-in-active-region 'start-level)
'region-start-level 'region))
org-loop-over-headlines-in-active-region)
(org-map-entries
`(org-deadline ',remove ,time)
org-loop-over-headlines-in-active-region
cl (if (outline-invisible-p) (org-end-of-subtree nil t))))
(let* ((old-date (org-entry-get nil "DEADLINE"))
(repeater (and old-date
(string-match
"\\([.+-]+[0-9]+[hdwmy]\\(?:[/ ][-+]?[0-9]+[hdwmy]\\)?\\) ?"
old-date)
(match-string 1 old-date))))
(if remove
(progn
(when (and old-date org-log-redeadline)
(org-add-log-setup 'deldeadline nil old-date 'findpos
org-log-redeadline))
(org-remove-timestamp-with-keyword org-deadline-string)
(message "Item no longer has a deadline."))
(org-add-planning-info 'deadline time 'closed)
(when (and old-date org-log-redeadline
(not (equal old-date
(substring org-last-inserted-timestamp 1 -1))))
(org-add-log-setup 'redeadline nil old-date 'findpos
org-log-redeadline))
(when repeater
(save-excursion
(org-back-to-heading t)
(when (re-search-forward (concat org-deadline-string " "
org-last-inserted-timestamp)
(save-excursion
(outline-next-heading) (point)) t)
(goto-char (1- (match-end 0)))
(insert " " repeater)
(setq org-last-inserted-timestamp
(concat (substring org-last-inserted-timestamp 0 -1)
" " repeater
(substring org-last-inserted-timestamp -1))))))
(message "Deadline on %s" org-last-inserted-timestamp)))))
The following code should do the trick. It's just a matter of asking the time separately and them passing it yourself to the org-deadline function.
(defun org/deadline (remove)
"like `org-deadline', except ask only once."
(interactive "P")
(unless remove (with-temp-buffer (org-time-stamp nil)))
(org-deadline remove org-last-inserted-timestamp))
(global-set-key [remap org-deadline] 'org/deadline)
EDIT: Simplified the function.

un-camelCase code not working

camelCase.el emacswiki has a function to un-camelcase. But It doesn't seem to work. I added that piece to the camelCase.el itself. But can't get it to work.
What am I missing ? Did anyone else have the same problem ?
EDIT : I have added last two functions, one of which is the function that doesn't work
(defun camelCase-downcase-word (count)
"Make word starting at point lowercase, leaving point after word."
(interactive "*p")
(let ((start (point)))
(camelCase-forward-word count)
(downcase-region start (point))))
(defun un-camelcase-string (s &optional sep start)
"Convert CamelCase string S to lower case with word separator SEP.
Default for SEP is a hyphen \"-\".
If third argument START is non-nil, convert words after that
index in STRING."
(let ((case-fold-search nil))
(while (string-match "[A-Z]" s (or start 1))
(setq s (replace-match (concat (or sep "_")
(downcase (match-string 0 s)))
t nil s)))
(downcase s)))
(provide 'camelCase)
Other than the misleading doc-string (it actually defaults to "_", not "-" for the separator), the definition of un-camelcase-string you provide works. Can you give us more details about how it fails and under what circumstances?

Emacs Auto Load Color Theme by Time

Can I let Emacs automatically load theme ? or do certain command at customized time ? Say what I want is to M-x load-theme RET solarized-light when I am at office at 9:00am and M-x laod-theme RET solarized-dark when I am back home and continued on emacs at 8:00pm.
To expand on #Anton Kovalenko's answer, you can get the current time using the current-time-string elisp function and extracting the current time of day in hours.
If you want to write a full implementation, you could do something like (Warning, not debugged):
;; <Color theme initialization code>
(setq current-theme '(color-theme-solarized-light))
(defun synchronize-theme ()
(setq hour
(string-to-number
(substring (current-time-string) 11 13)))
(if (member hour (number-sequence 6 17))
(setq now '(color-theme-solarized-light))
(setq now '(color-theme-solarized-dark)))
(if (equal now current-theme)
nil
(setq current-theme now)
(eval now) ) ) ;; end of (defun ...
(run-with-timer 0 3600 synchronize-theme)
For more info on the functions used, see the following sections of the emacs manual:
Time of day
Strings
String Conversions
Idle Timers
Contains
Number Sequence
Another (very elegant) solution is theme-changer.
Given a location and day/night color themes, this file provides a change-theme function that selects the appropriate theme based on whether it is day or night. It will continue to change themes at sunrise and sunset. To install:
Set the location:
(setq calendar-location-name "Dallas, TX")
(setq calendar-latitude 32.85)
(setq calendar-longitude -96.85)
Specify the day and night themes:
(require 'theme-changer)
(change-theme 'tango 'tango-dark)
The project is hosted on Github, and can be installed through melpa.
You can use this snippet of code to do what you want.
(defvar install-theme-loading-times nil
"An association list of time strings and theme names.
The themes will be loaded at the specified time every day.")
(defvar install-theme-timers nil)
(defun install-theme-loading-at-times ()
"Set up theme loading according to `install-theme-loading-at-times`"
(interactive)
(dolist (timer install-theme-timers)
(cancel-timer timer))
(setq install-theme-timers nil)
(dolist (time-theme install-theme-loading-times)
(add-to-list 'install-theme-timers
(run-at-time (car time-theme) (* 60 60 24) 'load-theme (cdr time-theme)))))
Just customize the variable install-theme-loading-times as desired:
(setq install-theme-loading-times '(("9:00am" . solarized-light)
("8:00pm" . solarized-dark)))
You can start with run-with-timer function:
(run-with-timer SECS REPEAT FUNCTION &rest ARGS)
Perform an action after a delay of SECS seconds.
Repeat the action every REPEAT seconds, if REPEAT is non-nil.
SECS and REPEAT may be integers or floating point numbers.
The action is to call FUNCTION with arguments ARGS.
This function returns a timer object which you can use in `cancel-timer'.
Schedule a function to run every minute or so, which will check
current time and call load-theme when appropriate (don't switch
theme every minute, even if it's reloading the current theme).
Found this simple code that works for doom emacs. Put this in the config file:
(load-theme 'solarized-light t t) ;;load light theme
(run-at-time "09:00" (* 60 60 24) (lambda () (enable-theme 'solarized-light)))
(load-theme 'solarized-dark t t) ;;load dark theme
(run-at-time "20:00" (* 60 60 24) (lambda () (enable-theme 'solarized-dark)))
replace light and dark themes with your choice. time can also be changed from 9am/8pm in 24-hour format.
source and credit: https://parasurv.neocities.org/emacs/change-emacs-theme-depending-on-time.html
This implementation changes theme based on sunrise and sunset times of the latitude and longitude you provide. The only dependency is solar.el which is released with Emacs (IIRC).
(I think the code can probably be shorter here.)
;; theme changing at sunrises and sunsets according to lat and long
(require 'solar)
(defun today-date-integer (offset)
"Returns today's date in a list of integers, i.e. month, date, and year, in system time."
(let* ((date (mapcar
(lambda (pattern)
(string-to-number (format-time-string pattern)))
'("%m" "%d" "%Y"))))
(setcar
(nthcdr
1
date)
(+ offset (nth 1 date)))
date))
(defun current-time-decimal ()
(let* ((current-min-fraction (/ (string-to-number (format-time-string "%M")) 60.0))
(current-hour (string-to-number (format-time-string "%H"))))
(+ current-hour current-min-fraction)))
(defun next-alarm-time (sunrise-time sunset-time)
(let* ((current-time (current-time-decimal)))
(cond ((< current-time sunrise-time)
(- sunrise-time current-time))
((and (>= current-time sunrise-time)
(< current-time sunset-time))
(- sunset-time current-time))
((>= current-time sunset-time)
(let ((tomorrow-sunrise-time (car (car (solar-sunrise-sunset (today-date-integer 1))))))
(- (+ 24 tomorrow-sunrise-time) current-time))))))
(defun to-seconds (hour) (* hour 60 60))
(defun change-theme (light-theme dark-theme coor)
(let* ((_ (setq calendar-latitude (car coor)))
( _ (setq calendar-longitude (nth 1 coor)))
(today-date (today-date-integer 0))
(sunrise-sunset-list (solar-sunrise-sunset today-date))
(sunrise-time (car (car sunrise-sunset-list)))
(sunset-time (car (nth 1 sunrise-sunset-list)))
(current-time (current-time-decimal))
(current-theme (if (or (< current-time sunrise-time) (> current-time sunset-time))
dark-theme
light-theme))
(next-alarm-t (next-alarm-time sunrise-time sunset-time)))
(cancel-function-timers 'change-theme)
(load-theme current-theme t)
(run-at-time
(to-seconds next-alarm-t) nil 'change-theme light-theme dark-theme coor)))
(change-theme 'solarized-gruvbox-light 'solarized-gruvbox-dark '(47.6062 -122.3321))

viper-insert wrong number of arguments error

I have the following function and keybinding in my .viper file:
(defun th-change-to-regexp (regexp)
(interactive "s")
(kill-region (point) (progn
(re-search-forward regexp nil nil 1)
(- (point) 1)))
(backward-char)
(viper-insert))
(define-key viper-vi-global-user-map "ct" 'th-change-to-regexp)
I'm getting the following error on the viper-insert command I think -
Wrong number of arguments: #[(arg) "Ä \210^H\211^X\204^M^#Å\202(^#^H:\203'#\203^^^#H
#Æ\232\203\"^#Å\202(^#^H#\202(^#^H)^YÇÈ ÉÊ\211\211¯^F!\210Ë=\203S# \211^[ÌV
\205O^#ÊÍÎ\217\210^KS\211^S\202>^#)\202U^#Ï )\207"
[arg val viper-intermediate-command count viper-set-complex-command-for-undo 1 (nil)
viper-set-destructive-command viper-insert 114 ...] 8 ("/contrib/projects/emacs23/32bit
/share/emacs/23.1/lisp/emulation/viper-cmd.elc" . 54774) "P"], 0
I'm not a viper user, so I could be completely off about this, but viper-insert takes 1 required argument, and you are not giving it any arguments. You could send it the current prefix argument with
(viper-insert current-prefix-arg)