;; For reference, the difference between symbol and lambda form of the macros:
;; http://stackoverflow.com/questions/753459/emacs-getting-readable-keyboard-macros
;; You always want symbol form, i.e. name-last-kbd-macro
;; only show matches
(defun occurrences (regexp &rest ignore)
"Show all matches for REGEXP in an `occur' buffer."
;; keep text covered by occur-prefix and match text-properties
(interactive (occur-read-primary-args))
(occur regexp)
(with-current-buffer (get-buffer "*Occur*")
(let ((inhibit-read-only t)
delete-from
pos)
(save-excursion
(while (setq pos (next-property-change (point)))
(goto-char pos)
(if (not (or (get-text-property (point) 'occur-prefix)
(get-text-property (point) 'occur-match)))
(if delete-from
(delete-region delete-from (point))
(setq delete-from (point)))
(when delete-from
(delete-region delete-from (point))
(if (get-text-property (point) 'occur-prefix)
(insert "\n")
(insert " ")))
(setq delete-from nil)))))))
(fset 'org-clocktable-daystep-remove-table-formula
[?\C-s ?# ?+ ?T ?B ?L ?F ?M ?\C-a ?\C-k ?\C-k ?\C-k ?| ?- tab])
(fset 'org-clocktable-daystep-add-date-column
[?\C-s ?d ?a ?i ?l ?y ? ?r ?e ?p ?o ?r ?t ?: return ?\C-a ?\C- ?\C-\M-f ?\C-\M-f ?\C-f ?\C-f ?\C-w ?\C- ?\C-e ?\C-w ?\C-n ?\C-f M-S-right ?\C-y tab C-down C-up])
(fset 'org-clocktable-daystep-remove-headline
[?\C-s ?h ?e ?a ?d ?l ?i ?n ?e ?\C-a ?\C- ?\C-n ?\C-n ?\C-w])
(fset 'ce 'calc-eval)
;; Eval the region at the cursor point (i.e. just the variable)
(fset 'eval-at-cursor "\243\C-c\C-r\C-f\C-b")
;; Enclose a region in an anonymous function
(fset 'javascript-region-2-anonymous-function
[?\C-w ?f ?u ?n ?c ?t ?i ?o ?n ?\( ?\C-f ? ?\{ return ?\C-y return ?\C-f ?\; left ?\C-\M-p ?\C-f ?\C-f ?r ?e ?t ?u ?r ?n ?\M- tab])
;; Delete matched pair of parentheses
(fset 'unnest-enclosed-parens
[?\C- ?\C-\M-n ?\C-g backspace ?\C-x ?\C-x ?\C-g ?\C-d])
;; Enclose the sexp in front of the cursor within round brackets
(fset 'nest-outer-round-parens
[?\C- ?\C-\M-f ?\( ?\C-\M-b ?\C-f])
;; Enclose the sexp in front of the cursor within square brackets
(fset 'nest-outer-square-parens
[?\C- ?\C-\M-n ?\[])
;; Enclose the sexp in front of the cursor within curly brackets
(fset 'nest-outer-curly-parens
[?\C- ?\C-\M-n ?\{])
;; Add another quoted argument (separated by comma)
(fset 'add-quoted-argument
"\C-f, \"")
(fset 'add-single-quoted-argument
"\C-f, '")
;; Old version with kill-visual-line
;;(fset 'copy-line-and-replace
;; [?\C-a ?\C-k ?\C-y return ?\C-y ?\C-x ?\C-x ?\M-% ?\C-u ?\C-x ?q return ?\C-u ?\C-x ?q return ?! ?\C-a])
;; Copy the entire line that you're on and query replace
(fset 'copy-line-and-replace
[?\C-a ?\M-x ?k ?i ?l ?l ?- ?w ?h ?o ?l ?e ?- ?l ?i ?n ?e ?\C-m ?\C-y return ?\C-y ?\C-x ?\C-x ?\M-% ?\C-u ?\C-x ?q return ?\C-u ?\C-x ?q return ?! ?\C-a])
;; Version with no replace
(fset 'copy-line
[?\C-a ?\M-x ?k ?i ?l ?l ?- ?w ?h ?o ?l ?e ?- ?l ?i ?n ?e ?\C-m ?\C-y return ?\C-y ?\C-x ?\C-x ?\C-a])
;; Eval a line in bash and print to new buffer
(fset 'shell-eval-line
[?\C-a ?\C- ?\C-e ?\M-w ?\C-a ?\M-! ?\C-y return])
;; Obsolete
;; (fset 'unix2date
;; (lambda (&optional arg) "Convert Unixtime to a date string. Example: Thu Mar 1 00:00:00 PST 2012 -> 1330588800"
;; (interactive "p")
;; (kmacro-exec-ring-item (quote ([67108896 5 134217847 32 45 32 21 134217761 100 97 116 101 32 45 45 100 97 116 101 32 34 64 25 5 13 5 6 4] 0 "%d")) arg)))
;; (put 'unix2date 'kmacro t)
(fset 'date2unix
(lambda (&optional arg) "Convert simple date string to unixtime. Example: 1330588800 -> Thu Mar 1 00:00:00 PST 2012"
(interactive "p")
(kmacro-exec-ring-item
(quote ([67108896 5 134217847 32 45 32 21 134217761 100 97 116 101 32 45 100 32 34 25 5 32 43 37 115 13 5 6 4] 0 "%d")) arg)))
(fset 'date2unix
(lambda (&optional arg) "Convert simple date string to unixtime. Example: 1330588800 -> Thu Mar 1 00:00:00 PST 2012"
(interactive "p")
(message (current-time-string (seconds-to-time arg)))))
(put 'date2unix 'kmacro t)
(defun unix2date (arg)
(interactive "p")
(insert (concat " - " (current-time-string (seconds-to-time (string-to-number (buffer-substring (region-beginning) (region-end))))))))
(defun unixtime2date (arg)
(interactive "p")
(message (format-time-string "%B %d, %Y %T UTC" (seconds-to-time (string-to-number (buffer-substring (region-beginning) (region-end)))))))
(defun date2unixtime (arg)
(interactive "p")
(message (current-time-string (encode-time 0 0 0 (string-to-number (substring (buffer-substring (region-beginning) (region-end)) 8 10)) (string-to-number (substring (buffer-substring (region-beginning) (region-end)) 5 7)) (string-to-number (substring (buffer-substring (region-beginning) (region-end)) 0 4))))))
; Older send-lin macro
;(fset 'python-shell-send-line
; [?\C-a ?\C- ?\C-e ?\C-c ?\C-r ?\C-g ?\C-a])
(fset 'slime-copy-to-process
[?\C-a ?\C- ?\C-e ?\M-w ?\C-\] ?\C-y return ?\C-\M-\] ?\C-a])
(defun eval-and-replace ()
"Replace the preceding sexp with its value."
(interactive)
(backward-kill-sexp)
(prin1 (eval (read (current-kill 0)))
(current-buffer)))
; This macro is supposed to send the region but it seems to act a little dodgy.
(fset 'send-region-macro
[C-up ?\C- C-down ?\C-c ?\C-r ?\C-g])
;; Custom vc-git-annotate-command
;; original uses date=iso
;; (defun vc-git-annotate-command (file buf &optional rev)
;; (let ((name (file-relative-name file)))
;; (vc-git-command buf 'async nil "blame" "--date=short" "-C" "-C" rev "--" name)))
;; can't be used properly by vc-annotate, I guess it's expecting a specific format
(fset 'envelop-parentheses
[?\( ?\C-\)])
(defun save-macro (name)
"save a macro. Take a name as argument
and save the last defined macro under
this name at the end of your .emacs"
(interactive "SName of the macro :") ; ask for the name of the macro
(name-last-kbd-macro name) ; use this name for the macro
(find-file "/media/sf_Conor/Dropbox/emacs/emacs24/elisp/emacs24.el") ; open ~/.emacs or other user init file
(goto-char (point-max)) ; go to the end of the .emacs
(newline) ; insert a newline
(insert-kbd-macro name) ; copy the macro
(newline) ; insert a newline
(switch-to-buffer nil)) ; return to the initial buffer
;; Count the words in the entire document
(defun count-words-buffer ()
"Count all the words in the buffer"
(interactive)
(count-words-region (point-min) (point-max)))
(defun remove-cr-and-lf ()
(interactive)
(end-of-line)
(delete-char 1)
(just-one-space)
(beginning-of-line))
(defun copy-line (&optional arg)
"Do a kill-line but copy rather than kill. This function directly calls
kill-line, so see documentation of kill-line for how to use it including prefix
argument and relevant variables. This function works by temporarily making the
buffer read-only, so I suggest setting kill-read-only-ok to t."
(interactive "P")
(toggle-read-only 1)
(kill-line arg)
(toggle-read-only 0))
(setq-default kill-read-only-ok t)
(defun zero-pad (&optional arg)
"When the cursor is placed in front of a number, augment the number to have zero-padding prefixing the number so that the number becomes 9 digits long."
(interactive "p")
(kill-word arg)
(insert (format "%009d" (string-to-number (car kill-ring-yank-pointer)))))
(defun back-window (&optional arg)
(interactive "P")
(other-window -1))
(defun remove-line-breaks ()
"Remove line endings in a paragraph."
(interactive)
(let ((fill-column (point-max)))
(fill-paragraph nil)))
(defun zap-to-regexp (arg regexp)
"Same as zap-to-char except that it zaps to the given regexp
instead of a char."
(interactive "p\nsZap to regexp: ")
(kill-region (point)
(progn
(re-search-forward regexp nil nil arg)
(point))))
(defun my-insert-file-name (filename &optional args)
"Insert name of file FILENAME into buffer after point.
Prefixed with \\[universal-argument], expand the file name to
its fully canocalized path. See `expand-file-name'.
Prefixed with \\[negative-argument], use relative path to file
name from current directory, `default-directory'. See
`file-relative-name'.
The default with no prefix is to insert the file name exactly as
it appears in the minibuffer prompt."
;; Based on insert-file in Emacs -- ashawley 20080926
(interactive "*fInsert file name: \nP")
(cond ((eq '- args)
(insert (file-relative-name filename)))
((not (null args))
(insert (expand-file-name filename)))
(t
(insert filename))))
;; code borrowed from http://emacs-fu.blogspot.com/2010/01/duplicating-lines-and-commenting-them.html
(defun djcb-duplicate-line (&optional commentfirst)
"comment line at point; if COMMENTFIRST is non-nil, comment the
original" (interactive)
(beginning-of-line)
(push-mark)
(end-of-line)
(let ((str (buffer-substring (region-beginning) (region-end))))
(when commentfirst
(comment-region (region-beginning) (region-end)))
(insert
(concat (if (= 0 (forward-line 1)) "" "\n") str "\n"))
(forward-line -1)))
(defun my-skewer-eval-line (vis)
"Send the current line to the inferior ESS process.
Arg has same meaning as for `ess-eval-region'."
(interactive "P")
(save-excursion
(end-of-line)
(let ((end (point)))
(beginning-of-line)
(princ (concat "Loading line:") t)
(skewer-input-sender (skewer-repl-process) (buffer-substring (point) end)))))
(defun my-skewer-eval-region (vis)
(interactive "P")
(save-excursion
(let ((end (point)))
(princ (concat "Loading line:") t)
(skewer-input-sender (skewer-repl-process) (buffer-substring (region-beginning) (region-end))))))
(defun move-text-internal (arg)
(cond
((and mark-active transient-mark-mode)
(if (> (point) (mark))
(exchange-point-and-mark))
(let ((column (current-column))
(text (delete-and-extract-region (point) (mark))))
(forward-line arg)
(move-to-column column t)
(set-mark (point))
(insert text)
(exchange-point-and-mark)
(setq deactivate-mark nil)))
(t
(let ((column (current-column)))
(beginning-of-line)
(when (or (> arg 0) (not (bobp)))
(forward-line)
(when (or (< arg 0) (not (eobp)))
(transpose-lines arg))
(forward-line -1))
(move-to-column column t)))))
(defun move-text-down (arg)
"Move region (transient-mark-mode active) or current line
arg lines down."
(interactive "*p")
(move-text-internal arg))
(defun move-text-up (arg)
"Move region (transient-mark-mode active) or current line
arg lines up."
(interactive "*p")
(move-text-internal (- arg))
;; (vertical-motion -1)
)
(defun conor-mydelete ()
"Delete the failed portion of the search string, or the last char if successful. Stolen from http://emacs.stackexchange.com/q/10359/6866"
(interactive)
(with-isearch-suspended
(setq isearch-new-string
(substring
isearch-string 0 (or (isearch-fail-pos) (1- (length isearch-string))))
isearch-new-message
(mapconcat 'isearch-text-char-description isearch-new-string ""))))
;; This is to allow highlighting in compiliation buffers
;; stolen from http://stackoverflow.com/a/3072831/77298
;; (use-package ansi-color)
;; (defun colorize-compilation-buffer ()
;; (toggle-read-only)
;; (ansi-color-apply-on-region (point-min) (point-max))
;; (toggle-read-only))
;; (add-hook 'compilation-filter-hook 'colorize-compilation-buffer)
(defun my/vsplit-last-buffer (prefix)
"Split the window vertically and display the previous buffer."
(interactive "p")
(split-window-vertically)
(other-window 1 nil)
(if (= prefix 1)
(switch-to-next-buffer)))
(defun my/hsplit-last-buffer (prefix)
"Split the window horizontally and display the previous buffer."
(interactive "p")
(split-window-horizontally)
(other-window 1 nil)
(if (= prefix 1) (switch-to-next-buffer)))
(defun my/smarter-move-beginning-of-line (arg)
"Move point back to indentation of beginning of line.
Move point to the first non-whitespace character on this line.
If point is already there, move to the beginning of the line.
Effectively toggle between the first non-whitespace character and
the beginning of the line.
If ARG is not nil or 1, move forward ARG - 1 lines first. If
point reaches the beginning or end of the buffer, stop there."
(interactive "^p")
(setq arg (or arg 1))
;; Move lines first
(when (/= arg 1)
(let ((line-move-visual nil))
(forward-line (1- arg))))
(let ((orig-point (point)))
(back-to-indentation)
(when (= orig-point (point))
(move-beginning-of-line 1))))
(defun camel-to-dot ()
"Convert camelCase to dot.separated"
(interactive)
(progn
(replace-regexp "\\([A-Z]\\)" ".\\1" nil (region-beginning) (region-end))
(downcase-region (region-beginning) (region-end))))
(defun camel-to-snake ()
"Convert camelCase to snake_case"
(interactive)
(progn
(replace-regexp "\\([a-z]+\\)\\([A-Z]\\)" "\\1_\\2" nil (region-beginning) (region-end))
(downcase-region (region-beginning) (region-end))))
(defun snake-to-camel (prefix)
"Convert snake_case to camelCase"
(interactive "p")
(save-excursion
(let ((reg-beg (region-beginning))
(reg-end (region-end)))
(progn
(replace-regexp "_" " " nil reg-beg reg-end)
(capitalize-region reg-beg reg-end)
(if (= prefix 4)
(progn
(goto-char reg-beg)
(insert "\"")
(goto-char (+ 1 reg-end))
(insert "\"")))))))
(defvar conornash/say-what-im-doing-common-commands
'(
backward-char
delete-backward-char
execute-extended-command
forward-char
keyboard-quit
newline
next-line
previous-line
self-insert-command
)
"These comands will not be spoken out loud, as they occur so frequently and repeatedly.")
(defvar conornash/say-what-im-doing-shell-command "say"
"This is the command-line program that will be used for text-to-speech.")
(defun conornash/say-what-im-doing-command-hook ()
"This is the function that will be added to `post-command-hook'."
(if (not (member this-command conornash/say-what-im-doing-common-commands))
(start-process "my_process"
nil conornash/say-what-im-doing-shell-command
(replace-regexp-in-string "-" " " (format "%s" this-command)))))
;;;###autoload
(define-minor-mode conornash/say-what-im-doing-mode
"This is a mode to make emacs say every command you invoke out
loud. This uses OS X's \"say\" by default, but can be
configured to use a different command line program - see
conornash/say-what-im-doing-shell-command."
:lighter " say"
:global t
(if conornash/say-what-im-doing-mode
(add-hook 'post-command-hook 'conornash/say-what-im-doing-command-hook)
(remove-hook 'post-command-hook 'conornash/say-what-im-doing-command-hook)))
(provide 'conornash/say-what-im-doing-mode)
(defun org-dblock-write:rangereport (params)
"Display day-by-day time reports."
(let* ((ts (plist-get params :tstart))
(te (plist-get params :tend))
(start (time-to-seconds
(apply 'encode-time (org-parse-time-string ts))))
(end (time-to-seconds
(apply 'encode-time (org-parse-time-string te))))
day-numbers)
(setq params (plist-put params :tstart nil))
(setq params (plist-put params :end nil))
(while (<= start end)
(save-excursion
(setq inner-time (org-clock-sum
(format-time-string (car org-time-stamp-formats) (seconds-to-time start))
(format-time-string (car org-time-stamp-formats) (seconds-to-time end))))
(insert "\n"
(concat (format-time-string (car org-time-stamp-formats)
(seconds-to-time start)) " | " (int-to-string inner-time)))
(setq start (+ 86400 start)
inner-time 0)))))
(defun conornash/org-clock-get-table-data (file params)
"Get the clocktable data for file FILE, with parameters PARAMS.
FILE is only for identification - this function assumes that
the correct buffer is current, and that the wanted restriction is
in place.
The return value will be a list with the file name and the total
file time (in minutes) as 1st and 2nd elements. The third element
of this list will be a list of headline entries. Each entry has the
following structure:
(LEVEL HEADLINE TIMESTAMP TIME)
LEVEL: The level of the headline, as an integer. This will be
the reduced leve, so 1,2,3,... even if only odd levels
are being used.
HEADLINE: The text of the headline. Depending on PARAMS, this may
already be formatted like a link.
TIMESTAMP: If PARAMS require it, this will be a time stamp found in the
entry, any of SCHEDULED, DEADLINE, NORMAL, or first inactive,
in this sequence.
TIME: The sum of all time spend in this tree, in minutes. This time
will of cause be restricted to the time block and tags match
specified in PARAMS."
(let* ((maxlevel (or (plist-get params :maxlevel) 3))
(timestamp (plist-get params :timestamp))
(ts (plist-get params :tstart))
(te (plist-get params :tend))
(ws (plist-get params :wstart))
(ms (plist-get params :mstart))
(block (plist-get params :block))
(link (plist-get params :link))
(tags (plist-get params :tags))
(properties (plist-get params :properties))
(inherit-property-p (plist-get params :inherit-props))
todo-only
(matcher (if tags (cdr (org-make-tags-matcher tags))))
cc range-text st p time level hdl props tsp tbl)
(setq org-clock-file-total-minutes nil)
(when block
(setq cc (org-clock-special-range block nil t ws ms)
ts (car cc) te (nth 1 cc) range-text (nth 2 cc)))
(when (integerp ts) (setq ts (calendar-gregorian-from-absolute ts)))
(when (integerp te) (setq te (calendar-gregorian-from-absolute te)))
(when (and ts (listp ts))
(setq ts (format "%4d-%02d-%02d" (nth 2 ts) (car ts) (nth 1 ts))))
(when (and te (listp te))
(setq te (format "%4d-%02d-%02d" (nth 2 te) (car te) (nth 1 te))))
;; Now the times are strings we can parse.
(if ts (setq ts (org-matcher-time ts)))
(if te (setq te (org-matcher-time te)))
(save-excursion
(org-clock-sum ts te
(unless (null matcher)
(lambda ()
(let* ((tags-list (org-get-tags-at))
(org-scanner-tags tags-list)
(org-trust-scanner-tags t))
(eval matcher)))))
(goto-char (point-min))
(setq st t)
(while (or (and (bobp) (prog1 st (setq st nil))
(get-text-property (point) :org-clock-minutes)
(setq p (point-min)))
(setq p (next-single-property-change
(point) :org-clock-minutes)))
(goto-char p)
(when (setq time (get-text-property p :org-clock-minutes))
(save-excursion
(beginning-of-line 1)
(when (and (looking-at "\\(\\*+\\)[ \t]+\\(.*?\\)\\([ \t]+:[[:alnum:]_@#%:]+:\\)?[ \t]*$")
(setq level (org-reduced-level
(- (match-end 1) (match-beginning 1))))
(<= level maxlevel))
(setq hdl (if (not link)
(match-string 2)
(org-make-link-string
(format "file:%s::%s"
(buffer-file-name)
(save-match-data
(match-string 2)))
(org-make-org-heading-search-string
(replace-regexp-in-string
org-bracket-link-regexp
(lambda (m) (or (match-string 3 m)
(match-string 1 m)))
(match-string 2)))))
tsp (when timestamp
(setq props (org-entry-properties (point)))
(or (cdr (assoc "SCHEDULED" props))
(cdr (assoc "DEADLINE" props))
(cdr (assoc "TIMESTAMP" props))
(cdr (assoc "TIMESTAMP_IA" props))))
props (when properties
(remove nil
(mapcar
(lambda (p)
(when (org-entry-get (point) p inherit-property-p)
(cons p (org-entry-get (point) p inherit-property-p))))
properties))))
(when (> time 0) (push (list level hdl tsp time props) tbl))))))
(setq tbl (nreverse tbl))
(list file org-clock-file-total-minutes tbl))))
(defun conornash/shell-command-do-it (pointed marked)
(interactive "r")
(shell-command (buffer-substring pointed marked)))
(defun dired-grep-marked-files ()
"`i` case insensitive; `n` print line number;
`I` ignore binary files; `E` extended regular expressions."
(interactive)
(let* ((files (dired-get-marked-files))
(search-term (read-string "regex: "))
(grep-command
(concat
grep-program
" "
"-inIE --color=always -C2"
" "
search-term
" "
(mapconcat 'shell-quote-argument files " "))))
(when (and files search-term grep-command)
(compilation-start grep-command 'grep-mode (lambda (mode) "*grep*") nil))))
(require 'server)
(defun generate-secure-password ()
(interactive)
(let* ((raw-auth-key (server-generate-key))
(replaced-auth-key (s-replace-regexp "[][%/\\\"'`,.(){}]" "" raw-auth-key))
(auth-key (s-left 16 replaced-auth-key)))
(if (called-interactively-p 'interactive)
(progn (insert auth-key)
(kill-new auth-key)))
auth-key))
(defun noccur ()
(interactive)
(let ((orig-re-search-forward (symbol-function 're-search-forward)))
(fset 're-search-forward 'noccur-re-search-forward)
(unwind-protect
(call-interactively 'occur)
(fset 're-search-forward orig-re-search-forward))))
(defun noccur-re-search-forward (regexp bound noerror &optional count)
(unless (eq (aref regexp 0) ?^)
(setq regexp (concat ".*" regexp)))
(while (and (not (eobp))
(looking-at regexp))
(forward-line 1))
(if (eobp)
nil
(set-match-data (list (line-beginning-position)
(line-end-position)))
(line-end-position)))