2017-05-28 12:32:48 +02:00
|
|
|
|
;;; Functions
|
|
|
|
|
|
2017-06-16 16:29:52 +02:00
|
|
|
|
;;; Notes on mark and region: to get a consistent behaviour regardless of
|
|
|
|
|
;;; Transient mode, check `(use-region-p)'. It will work as expected if
|
2017-05-28 12:32:48 +02:00
|
|
|
|
;;; transient. If not, it will always be true as soon as the mark has been set
|
|
|
|
|
;;; once; so you need to make sure the mark is set as you want beforehand (e.g.
|
|
|
|
|
;;; whole buffer, single line...). This is the behaviour of `sort-lines'.
|
|
|
|
|
;;;
|
|
|
|
|
;;; The clean way to get static region boundaries and fallback on buffer boundaries:
|
|
|
|
|
;;
|
|
|
|
|
;; (let (start end)
|
|
|
|
|
;; (if (use-region-p)
|
|
|
|
|
;; (setq start (region-beginning) end (region-end))
|
|
|
|
|
;; (setq start (point-min) end (point-max)))
|
|
|
|
|
;;
|
2017-06-16 16:29:52 +02:00
|
|
|
|
;;; If several commands act on region and the region size/pos is susceptible to change:
|
2017-05-28 12:32:48 +02:00
|
|
|
|
;;
|
|
|
|
|
;; (let ((start (set-marker (make-marker) (if (use-region-p) (region-beginning) (point-min))))
|
|
|
|
|
;; (end (set-marker (make-marker) (if (use-region-p) (region-end) (point-end)))))
|
2017-05-14 08:30:34 +02:00
|
|
|
|
;;
|
2017-05-28 12:32:48 +02:00
|
|
|
|
;;; For commands that only work on regions:
|
|
|
|
|
;;
|
|
|
|
|
;; (defun count-lines-region (start end)
|
|
|
|
|
;; "Print number of lines and characters in the region."
|
|
|
|
|
;; (interactive "r")
|
2017-06-16 16:29:52 +02:00
|
|
|
|
;; ...
|
2014-02-26 18:04:00 +01:00
|
|
|
|
|
2017-05-28 12:03:28 +02:00
|
|
|
|
(defun beginning-of-next-defun ()
|
|
|
|
|
"Move forward to the beginning of a defun.
|
|
|
|
|
Useful when bound to a key opposed to `beginning-of-defun'."
|
2017-06-03 17:39:04 +02:00
|
|
|
|
(interactive)
|
2017-05-28 12:03:28 +02:00
|
|
|
|
(beginning-of-defun -1))
|
2017-06-20 20:38:59 +02:00
|
|
|
|
(global-set-key (kbd "C-M-e") 'beginning-of-next-defun)
|
2017-05-28 12:03:28 +02:00
|
|
|
|
|
2014-02-24 12:22:22 +01:00
|
|
|
|
(defun call-process-to-string (program &rest args)
|
|
|
|
|
"Call PROGRAM with ARGS and return output."
|
|
|
|
|
(with-output-to-string
|
2017-06-26 18:13:28 +02:00
|
|
|
|
(with-current-buffer standard-output
|
2014-02-24 12:22:22 +01:00
|
|
|
|
(apply 'call-process program nil t nil args))))
|
|
|
|
|
|
2014-02-21 19:38:49 +01:00
|
|
|
|
(defun count-occurences (regex string)
|
2017-05-24 00:27:02 +02:00
|
|
|
|
"Return number of times REGEX occurs in STRING.
|
2014-02-24 20:07:25 +01:00
|
|
|
|
If you want to operate on buffer, use `how-many' instead."
|
2014-02-21 19:38:49 +01:00
|
|
|
|
(let ((start 0) (matches 0))
|
|
|
|
|
(while (string-match regex string start)
|
|
|
|
|
(setq start (match-end 0))
|
|
|
|
|
(setq matches (1+ matches)))
|
|
|
|
|
matches))
|
|
|
|
|
|
2017-06-16 21:33:53 +02:00
|
|
|
|
(defun define-keys (map key def &rest bindings)
|
|
|
|
|
"Like `define-key' but allow for defining several bindings at once.
|
|
|
|
|
`KEY' must be acceptable for `kbd'."
|
|
|
|
|
(while key
|
|
|
|
|
(define-key map (kbd key) def)
|
|
|
|
|
(setq key (pop bindings)
|
|
|
|
|
def (pop bindings))))
|
|
|
|
|
|
2013-06-11 17:10:02 +02:00
|
|
|
|
(defun duplicate (arg)
|
2014-02-21 20:08:20 +01:00
|
|
|
|
"Duplicate the current line or region ARG times.
|
2013-06-11 17:10:02 +02:00
|
|
|
|
If there's no region, the current line will be duplicated. However, if
|
|
|
|
|
there's a region, all lines that region covers will be duplicated."
|
|
|
|
|
(interactive "p")
|
|
|
|
|
(let (beg
|
|
|
|
|
end
|
|
|
|
|
(origin (point))
|
|
|
|
|
(auto-fill-p (symbol-value 'auto-fill-function)))
|
2017-05-24 22:44:11 +02:00
|
|
|
|
(when (and (use-region-p) (> (point) (mark)))
|
|
|
|
|
(exchange-point-and-mark))
|
2013-06-11 17:10:02 +02:00
|
|
|
|
(setq beg (line-beginning-position))
|
2017-05-24 22:44:11 +02:00
|
|
|
|
(when (use-region-p)
|
|
|
|
|
(exchange-point-and-mark))
|
2013-06-11 17:10:02 +02:00
|
|
|
|
(setq end (line-end-position))
|
|
|
|
|
(let ((region (buffer-substring-no-properties beg end)))
|
|
|
|
|
(auto-fill-mode -1)
|
|
|
|
|
(dotimes (i arg)
|
|
|
|
|
(goto-char end)
|
|
|
|
|
(newline)
|
|
|
|
|
(insert region)
|
|
|
|
|
(setq end (point)))
|
|
|
|
|
(if auto-fill-p (auto-fill-mode))
|
|
|
|
|
(goto-char (+ origin (* (length region) arg) arg)))))
|
2017-06-20 20:38:59 +02:00
|
|
|
|
(global-set-key (kbd "C-x M-d") 'duplicate)
|
2013-06-11 17:10:02 +02:00
|
|
|
|
|
2015-04-25 13:47:00 +02:00
|
|
|
|
(defun emacs-process-p (pid)
|
2017-05-24 00:27:02 +02:00
|
|
|
|
"If PID is the process ID of an Emacs process, return t, else nil.
|
2015-04-25 13:47:00 +02:00
|
|
|
|
Also returns nil if pid is nil."
|
|
|
|
|
(when pid
|
|
|
|
|
(let ((attributes (process-attributes pid)) (cmd))
|
|
|
|
|
(dolist (attr attributes)
|
|
|
|
|
(if (string= "comm" (car attr))
|
|
|
|
|
(setq cmd (cdr attr))))
|
|
|
|
|
(if (and cmd (or (string= "emacs" cmd) (string= "emacs.exe" cmd))) t))))
|
|
|
|
|
|
2014-03-10 00:11:46 +01:00
|
|
|
|
(defun escape-region (&optional regex to-string)
|
|
|
|
|
"Escape double-quotes and backslashes.
|
2017-05-08 11:57:40 +02:00
|
|
|
|
This is useful for writing Elisp strings containing those
|
2017-05-24 00:27:02 +02:00
|
|
|
|
characters. The optional parameters let you control the replacement of REGEX for
|
|
|
|
|
TO-STRING."
|
2014-03-10 00:11:46 +01:00
|
|
|
|
(interactive)
|
|
|
|
|
(unless regex (setq regex "\\([\"\\\\]\\)"))
|
|
|
|
|
(unless to-string (setq to-string "\\\\\\1"))
|
2017-05-24 22:44:11 +02:00
|
|
|
|
(while (re-search-forward regex (if (use-region-p) (region-end) (point-max)) t)
|
|
|
|
|
(replace-match to-string)))
|
2014-03-10 00:11:46 +01:00
|
|
|
|
|
2013-03-18 13:27:07 +01:00
|
|
|
|
(defun eval-and-replace ()
|
2013-06-11 17:10:02 +02:00
|
|
|
|
"Replace the last sexp with its value."
|
2013-03-18 13:27:07 +01:00
|
|
|
|
(interactive)
|
|
|
|
|
(backward-kill-sexp)
|
|
|
|
|
(condition-case nil
|
|
|
|
|
(prin1 (eval (read (current-kill 0)))
|
|
|
|
|
(current-buffer))
|
|
|
|
|
(error (message "Invalid expression")
|
|
|
|
|
(insert (current-kill 0)))))
|
2013-06-11 17:10:02 +02:00
|
|
|
|
|
2016-06-09 18:25:18 +02:00
|
|
|
|
(defun find-symbol-at-point ()
|
2017-05-05 20:53:05 +02:00
|
|
|
|
"Find directly the symbol at point, i.e. go to definition."
|
2016-06-09 18:25:18 +02:00
|
|
|
|
(interactive)
|
|
|
|
|
(let ((sym (symbol-at-point)))
|
|
|
|
|
(if (boundp sym)
|
2017-05-05 20:53:05 +02:00
|
|
|
|
(find-variable sym)
|
|
|
|
|
(find-function sym))))
|
2016-06-09 18:25:18 +02:00
|
|
|
|
|
2017-05-28 12:12:53 +02:00
|
|
|
|
(defun fmt ()
|
|
|
|
|
"(Un)tabify, indent and delete trailing whitespace.
|
|
|
|
|
Tabify if `indent-tabs-mode' is true, otherwise use spaces.
|
|
|
|
|
Work on buffer or region. Require `tabify-leading'."
|
|
|
|
|
(interactive)
|
|
|
|
|
(let ((start (set-marker (make-marker) (if (use-region-p) (region-beginning) (point-min))))
|
|
|
|
|
(end (set-marker (make-marker) (if (use-region-p) (region-end) (point-max)))))
|
|
|
|
|
(if indent-tabs-mode
|
|
|
|
|
(tabify-leading)
|
|
|
|
|
(untabify start end))
|
|
|
|
|
(indent-region start end)
|
|
|
|
|
(save-restriction
|
|
|
|
|
(narrow-to-region start end)
|
|
|
|
|
(delete-trailing-whitespace))))
|
|
|
|
|
|
2014-02-21 19:38:49 +01:00
|
|
|
|
(defun get-closest-pathname (&optional file)
|
2014-02-21 20:08:20 +01:00
|
|
|
|
"Get pathname of the first instance of FILE towards root.
|
2014-03-08 16:31:41 +01:00
|
|
|
|
If FILE is unspecified, look for 'Makefile'. If it does not find
|
2017-05-11 19:34:27 +02:00
|
|
|
|
FILE, return nil. This may not do the correct thing in presence
|
|
|
|
|
of links."
|
|
|
|
|
(let* ((pwd default-directory) (file (or file "Makefile")) (target (expand-file-name file pwd)))
|
|
|
|
|
(while
|
|
|
|
|
(unless (or (file-exists-p target) (equal pwd "/"))
|
|
|
|
|
(setq pwd (expand-file-name ".." pwd))
|
|
|
|
|
(setq target (expand-file-name file pwd))))
|
|
|
|
|
(if (file-exists-p target) target nil)))
|
2013-06-11 17:10:02 +02:00
|
|
|
|
|
2017-06-20 20:38:59 +02:00
|
|
|
|
(defun global-set-keys (key def &rest bindings)
|
|
|
|
|
"Like `global-set-key' but allow for defining several bindings at once.
|
|
|
|
|
`KEY' must be acceptable for `kbd'."
|
|
|
|
|
(while key
|
|
|
|
|
(global-set-key (kbd key) def)
|
|
|
|
|
(setq key (pop bindings)
|
|
|
|
|
def (pop bindings))))
|
|
|
|
|
|
2014-03-20 13:09:50 +01:00
|
|
|
|
(defun insert-and-indent (text)
|
|
|
|
|
"Insert indented TEXT at point."
|
|
|
|
|
(interactive "s Text: ")
|
|
|
|
|
(let ((oldpoint (point)))
|
|
|
|
|
(insert text)
|
|
|
|
|
(indent-region oldpoint (point))
|
|
|
|
|
(newline-and-indent)))
|
|
|
|
|
|
2014-03-08 11:01:29 +01:00
|
|
|
|
(defun 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
|
2016-06-08 14:05:10 +02:00
|
|
|
|
fully canonicalized path. See `expand-file-name'.
|
2014-03-08 11:01:29 +01:00
|
|
|
|
|
|
|
|
|
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))))
|
2013-09-30 19:59:13 +02:00
|
|
|
|
|
2017-06-16 21:33:53 +02:00
|
|
|
|
(defun local-set-keys (key def &rest bindings)
|
|
|
|
|
"Like `local-set-key' but allow for defining several bindings at once.
|
|
|
|
|
`KEY' must be acceptable for `kbd'."
|
|
|
|
|
(while key
|
|
|
|
|
(local-set-key (kbd key) def)
|
|
|
|
|
(setq key (pop bindings)
|
|
|
|
|
def (pop bindings))))
|
|
|
|
|
|
2014-03-09 12:42:27 +01:00
|
|
|
|
(defun mark-word-from-beginning (&optional arg allow-extend)
|
2017-05-24 00:27:02 +02:00
|
|
|
|
"Set the point at the beginning of the word and call `mark-word'.
|
|
|
|
|
ARG and ALLOW-EXTEND are the same."
|
2013-09-30 19:59:13 +02:00
|
|
|
|
(interactive "P\np")
|
|
|
|
|
(cond ((and allow-extend
|
|
|
|
|
(or (and (eq last-command this-command) (mark t))
|
|
|
|
|
(region-active-p)))
|
2014-03-09 12:42:27 +01:00
|
|
|
|
(mark-word arg allow-extend))
|
2013-09-30 19:59:13 +02:00
|
|
|
|
(t
|
2013-10-22 12:44:38 +02:00
|
|
|
|
;; The next line makes sure the word at point gets selected if point is
|
|
|
|
|
;; on the first letter. We need to ignore error if point is at EOF.
|
|
|
|
|
(ignore-errors (forward-char))
|
2013-09-30 19:59:13 +02:00
|
|
|
|
(backward-word)
|
2014-03-09 12:42:27 +01:00
|
|
|
|
(mark-word arg allow-extend))))
|
2017-06-20 20:38:59 +02:00
|
|
|
|
(global-set-key (kbd "M-@") 'mark-word-from-beginning)
|
2013-10-27 14:28:47 +01:00
|
|
|
|
|
2014-02-21 19:38:49 +01:00
|
|
|
|
(defun move-border-left (arg)
|
2014-02-21 20:08:20 +01:00
|
|
|
|
"Move window border in a natural manner.
|
|
|
|
|
If this is a window with its right edge being the edge of the
|
2014-02-21 19:38:49 +01:00
|
|
|
|
screen, enlarge the window horizontally. If this is a window with
|
|
|
|
|
its left edge being the edge of the screen, shrink the window
|
2014-02-21 20:08:20 +01:00
|
|
|
|
horizontally. Otherwise, default to enlarging horizontally.\n
|
2017-05-24 00:27:02 +02:00
|
|
|
|
Enlarge/Shrink by ARG columns, or 5 if ARG is nil."
|
2014-02-21 19:38:49 +01:00
|
|
|
|
(interactive "P")
|
|
|
|
|
(if (= (count-windows) 2)
|
|
|
|
|
(move-border-left-or-right arg t)))
|
2017-06-20 20:38:59 +02:00
|
|
|
|
(global-set-key (kbd "M-(") 'move-border-left)
|
2013-10-27 14:28:47 +01:00
|
|
|
|
|
2017-05-07 21:14:13 +02:00
|
|
|
|
(defun move-border-left-or-right (arg dir-left)
|
2017-05-24 00:27:02 +02:00
|
|
|
|
"Wrapper around ‘move-border-left’ and ‘move-border-right’.
|
|
|
|
|
ARG is the number of columns to move.
|
|
|
|
|
If DIR-LEFT is t, then move left, otherwise move right."
|
2013-10-27 14:28:47 +01:00
|
|
|
|
(interactive)
|
2017-05-24 00:27:02 +02:00
|
|
|
|
(unless arg (setq arg 5))
|
2017-05-07 21:14:13 +02:00
|
|
|
|
(let ((left-edge (= (car (window-edges)) 0)))
|
|
|
|
|
(if (or
|
|
|
|
|
(and left-edge dir-left)
|
|
|
|
|
(and (not left-edge) (not dir-left)))
|
2014-02-21 19:38:49 +01:00
|
|
|
|
(shrink-window arg t)
|
|
|
|
|
(enlarge-window arg t))))
|
2013-10-27 14:28:47 +01:00
|
|
|
|
|
2014-02-21 19:38:49 +01:00
|
|
|
|
(defun move-border-right (arg)
|
2014-02-21 20:08:20 +01:00
|
|
|
|
"See `move-border-left'."
|
2014-02-21 19:38:49 +01:00
|
|
|
|
(interactive "P")
|
|
|
|
|
(if (= (count-windows) 2)
|
|
|
|
|
(move-border-left-or-right arg nil)))
|
2017-06-20 20:38:59 +02:00
|
|
|
|
(global-set-key (kbd "M-)") 'move-border-right)
|
2013-10-27 14:28:47 +01:00
|
|
|
|
|
2017-05-28 12:32:48 +02:00
|
|
|
|
;;; Almost useless compared to Helm-file M-R. However helm does not change
|
|
|
|
|
;;; current directory.
|
2014-02-21 19:38:49 +01:00
|
|
|
|
(defun rename-buffer-and-file ()
|
|
|
|
|
"Renames current buffer and file it is visiting."
|
2014-02-12 18:31:00 +01:00
|
|
|
|
(interactive)
|
2014-02-21 19:38:49 +01:00
|
|
|
|
(let ((name (buffer-name))
|
|
|
|
|
(filename (buffer-file-name)))
|
|
|
|
|
(if (not (and filename (file-exists-p filename)))
|
|
|
|
|
(error "Buffer '%s' is not visiting a file!" name)
|
|
|
|
|
(let ((new-name (read-file-name "New name: " filename)))
|
|
|
|
|
(cond ((get-buffer new-name)
|
|
|
|
|
(error "A buffer named '%s' already exists!" new-name))
|
|
|
|
|
(t
|
|
|
|
|
(rename-file filename new-name 1)
|
|
|
|
|
(rename-buffer new-name)
|
|
|
|
|
(set-visited-file-name new-name)
|
|
|
|
|
(set-buffer-modified-p nil)
|
|
|
|
|
(message "File '%s' successfully renamed to '%s'" name (file-name-nondirectory new-name))))))))
|
2014-02-12 18:31:00 +01:00
|
|
|
|
|
2017-05-28 12:03:28 +02:00
|
|
|
|
(defun reset-fill-column ()
|
|
|
|
|
"Reset `fill-column' to its default value."
|
|
|
|
|
(setq fill-column (default-value 'fill-column)))
|
2014-02-12 18:49:41 +01:00
|
|
|
|
|
2014-02-21 19:38:49 +01:00
|
|
|
|
(defun shell-last-command ()
|
|
|
|
|
"Run last shell command."
|
|
|
|
|
(interactive)
|
|
|
|
|
(let ((last (car shell-command-history)))
|
|
|
|
|
(if last
|
|
|
|
|
(shell-command last)
|
2014-02-23 20:35:36 +01:00
|
|
|
|
(error "Shell command history is empty"))))
|
2017-06-20 20:38:59 +02:00
|
|
|
|
(global-set-key (kbd "C-M-!") 'shell-last-command)
|
2014-02-12 18:49:41 +01:00
|
|
|
|
|
2014-02-13 17:22:52 +01:00
|
|
|
|
(defun skeleton-make-markers ()
|
2014-02-21 20:08:20 +01:00
|
|
|
|
"Save last skeleton markers in a list.
|
|
|
|
|
Hook function for skeletons."
|
2014-02-13 17:22:52 +01:00
|
|
|
|
(while skeleton-markers
|
|
|
|
|
(set-marker (pop skeleton-markers) nil))
|
|
|
|
|
(setq skeleton-markers
|
|
|
|
|
(mapcar 'copy-marker (reverse skeleton-positions))))
|
2014-02-21 19:38:49 +01:00
|
|
|
|
|
2014-03-13 16:13:21 +01:00
|
|
|
|
(defvar skeleton-markers nil
|
2017-05-24 00:27:02 +02:00
|
|
|
|
"Markers for locations saved in `skeleton-positions'.")
|
2014-03-13 16:13:21 +01:00
|
|
|
|
|
2014-02-13 17:22:52 +01:00
|
|
|
|
(defun skeleton-next-position (&optional reverse)
|
2017-05-24 00:27:02 +02:00
|
|
|
|
"Move to next skeleton placeholder.
|
2017-05-28 12:03:28 +02:00
|
|
|
|
If REVERSE it t, move to previous placeholder."
|
2014-02-13 17:22:52 +01:00
|
|
|
|
(interactive "P")
|
|
|
|
|
(let ((positions (mapcar 'marker-position skeleton-markers))
|
2014-03-09 20:13:42 +01:00
|
|
|
|
(comp (if reverse '< '<=))
|
2017-05-28 12:03:28 +02:00
|
|
|
|
pos
|
|
|
|
|
prev)
|
2014-02-13 17:22:52 +01:00
|
|
|
|
(when positions
|
2014-03-09 20:13:42 +01:00
|
|
|
|
(setq pos (pop positions))
|
|
|
|
|
(while (and pos (funcall comp pos (point)))
|
|
|
|
|
(setq prev pos)
|
|
|
|
|
(setq pos (pop positions)))
|
|
|
|
|
(cond
|
|
|
|
|
((and reverse prev) (goto-char prev))
|
|
|
|
|
(reverse (goto-char (car (last skeleton-markers))))
|
|
|
|
|
(pos (goto-char pos))
|
|
|
|
|
(t (goto-char (car skeleton-markers)))))))
|
2014-02-13 15:56:13 +01:00
|
|
|
|
|
2015-09-12 12:02:53 +02:00
|
|
|
|
(defun sort-lines-unique (arg)
|
|
|
|
|
"Remove trailing white space, then duplicate lines, then sort the result.
|
2016-06-08 14:05:10 +02:00
|
|
|
|
Do not fold case with \\[universal-argument] or non-nil ARG."
|
2015-09-12 12:02:53 +02:00
|
|
|
|
(interactive "P")
|
2017-05-28 12:32:48 +02:00
|
|
|
|
(let ((start (set-marker (make-marker) (if (use-region-p) (region-beginning) (point-min))))
|
|
|
|
|
(end (set-marker (make-marker) (if (use-region-p) (region-end) (point-end)))))
|
2017-05-14 08:30:34 +02:00
|
|
|
|
(let ((sort-fold-case (if arg nil t)))
|
2017-05-24 22:44:11 +02:00
|
|
|
|
(delete-trailing-whitespace start end)
|
|
|
|
|
(delete-duplicate-lines start end)
|
|
|
|
|
(sort-lines nil start end))))
|
2014-02-18 12:13:18 +01:00
|
|
|
|
|
2017-05-23 19:06:06 +02:00
|
|
|
|
(defun spawn-terminal ()
|
|
|
|
|
"Spawn terminal asynchronously.
|
|
|
|
|
The SHELL_CD environement variable is set to `default-directory'.
|
|
|
|
|
The shell can use it to automatically change directory to it."
|
|
|
|
|
(interactive)
|
|
|
|
|
(let ((term (or (getenv "TERMCMD") "xterm")))
|
|
|
|
|
(when (executable-find term)
|
2017-05-27 16:18:06 +02:00
|
|
|
|
(start-process "dummy" nil "env" (concat "SHELL_CD=" (expand-file-name default-directory)) term))))
|
2017-05-23 19:06:06 +02:00
|
|
|
|
|
2014-02-21 19:38:49 +01:00
|
|
|
|
(defun swap-windows ()
|
2016-06-08 14:47:57 +02:00
|
|
|
|
"If 2 windows are up, swap them."
|
2014-02-21 19:38:49 +01:00
|
|
|
|
(interactive)
|
2016-06-08 14:47:57 +02:00
|
|
|
|
(unless (= 2 (count-windows))
|
|
|
|
|
(error "There are not 2 windows"))
|
|
|
|
|
(let* ((w1 (car (window-list)))
|
|
|
|
|
(w2 (nth 1 (window-list)))
|
|
|
|
|
(b1 (window-buffer w1))
|
|
|
|
|
(b2 (window-buffer w2))
|
|
|
|
|
(s1 (window-start w1))
|
|
|
|
|
(s2 (window-start w2)))
|
|
|
|
|
(set-window-buffer w1 b2)
|
|
|
|
|
(set-window-buffer w2 b1)
|
|
|
|
|
(set-window-start w1 s2)
|
|
|
|
|
(set-window-start w2 s1))
|
2014-02-21 19:38:49 +01:00
|
|
|
|
(other-window 1))
|
2017-06-20 20:38:59 +02:00
|
|
|
|
(global-set-key (kbd "C-x \\") 'swap-windows)
|
2014-02-21 15:23:25 +01:00
|
|
|
|
|
2017-07-27 15:43:45 +02:00
|
|
|
|
(defun switch-to-last-buffer ()
|
|
|
|
|
"Switch to last open buffer in current window."
|
|
|
|
|
(interactive)
|
|
|
|
|
(switch-to-buffer (other-buffer (current-buffer) 1)))
|
|
|
|
|
|
2014-10-24 14:08:37 +02:00
|
|
|
|
(defun tabify-leading ()
|
|
|
|
|
"Call `tabify' on leading spaces only.
|
|
|
|
|
Works on whole buffer if region is unactive."
|
|
|
|
|
(interactive)
|
|
|
|
|
(require 'tabify) ; Need this to initialize `tabify-regexp'.
|
|
|
|
|
(let ((tabify-regexp-old tabify-regexp) start end)
|
2017-05-24 22:44:11 +02:00
|
|
|
|
(if (use-region-p)
|
2014-10-24 15:10:21 +02:00
|
|
|
|
(setq start (region-beginning) end (region-end))
|
|
|
|
|
(setq start (point-min) end (point-max)))
|
|
|
|
|
(unwind-protect
|
|
|
|
|
(progn
|
|
|
|
|
(setq tabify-regexp "^\t* [ \t]+")
|
|
|
|
|
(tabify start end))
|
|
|
|
|
(setq tabify-regexp tabify-regexp-old))))
|
|
|
|
|
|
2017-07-27 15:43:45 +02:00
|
|
|
|
;; TODO: Store window configurations in a buffer-name-indexed alist? Not
|
|
|
|
|
;; sure that would ever be useful.
|
|
|
|
|
(defvar single-window--last-configuration nil "Last window configuration before calling `delete-other-windows'.")
|
|
|
|
|
(defun toggle-single-window ()
|
|
|
|
|
"Un-maximize current window.
|
|
|
|
|
If multiple windows are active, save window configuration and
|
|
|
|
|
delete other windows. If only one window is active and a window
|
|
|
|
|
configuration was previously save, restore that configuration."
|
|
|
|
|
(interactive)
|
|
|
|
|
(if (= (count-windows) 1)
|
|
|
|
|
(when single-window--last-configuration
|
|
|
|
|
(set-window-configuration single-window--last-configuration))
|
|
|
|
|
(setq single-window--last-configuration (current-window-configuration))
|
|
|
|
|
(delete-other-windows)))
|
|
|
|
|
|
2014-02-21 19:38:49 +01:00
|
|
|
|
(defun toggle-window-dedicated ()
|
|
|
|
|
"Toggle whether the current active window is dedicated or not.
|
|
|
|
|
Run it in each window you want to 'freeze', i.e. prevent Emacs
|
|
|
|
|
from acting on it."
|
|
|
|
|
(interactive)
|
|
|
|
|
(message
|
2017-05-24 00:27:02 +02:00
|
|
|
|
(if (let ((window (get-buffer-window (current-buffer))))
|
2014-02-21 19:38:49 +01:00
|
|
|
|
(set-window-dedicated-p window
|
|
|
|
|
(not (window-dedicated-p window))))
|
|
|
|
|
"Window '%s' is dedicated"
|
|
|
|
|
"Window '%s' is normal")
|
|
|
|
|
(current-buffer)))
|
2017-06-20 20:38:59 +02:00
|
|
|
|
(global-set-key [pause] 'toggle-window-dedicated)
|
2014-02-21 15:23:25 +01:00
|
|
|
|
|
2014-02-21 19:38:49 +01:00
|
|
|
|
(defun toggle-window-split ()
|
2014-02-21 20:08:20 +01:00
|
|
|
|
"Switch between vertical and horizontal split.
|
|
|
|
|
It only works for frames with exactly two windows."
|
2014-02-21 19:38:49 +01:00
|
|
|
|
(interactive)
|
|
|
|
|
(if (= (count-windows) 2)
|
|
|
|
|
(let* ((this-win-buffer (window-buffer))
|
|
|
|
|
(next-win-buffer (window-buffer (next-window)))
|
|
|
|
|
(this-win-edges (window-edges (selected-window)))
|
|
|
|
|
(next-win-edges (window-edges (next-window)))
|
|
|
|
|
(this-win-2nd (not (and (<= (car this-win-edges)
|
|
|
|
|
(car next-win-edges))
|
|
|
|
|
(<= (cadr this-win-edges)
|
|
|
|
|
(cadr next-win-edges)))))
|
|
|
|
|
(splitter
|
|
|
|
|
(if (= (car this-win-edges)
|
|
|
|
|
(car (window-edges (next-window))))
|
|
|
|
|
'split-window-horizontally
|
|
|
|
|
'split-window-vertically)))
|
|
|
|
|
(delete-other-windows)
|
|
|
|
|
(let ((first-win (selected-window)))
|
|
|
|
|
(funcall splitter)
|
|
|
|
|
(if this-win-2nd (other-window 1))
|
|
|
|
|
(set-window-buffer (selected-window) this-win-buffer)
|
|
|
|
|
(set-window-buffer (next-window) next-win-buffer)
|
|
|
|
|
(select-window first-win)
|
|
|
|
|
(if this-win-2nd (other-window 1))))))
|
2017-06-20 20:38:59 +02:00
|
|
|
|
(global-set-key (kbd "C-x C-\\") 'toggle-window-split)
|
2014-02-21 15:23:25 +01:00
|
|
|
|
|
2014-02-21 19:38:49 +01:00
|
|
|
|
(defun toggle-word-delim ()
|
2014-02-21 20:08:20 +01:00
|
|
|
|
"Make underscore part of the word syntax or not.
|
|
|
|
|
This does not interfere with `subword-mode'."
|
2014-02-21 15:23:25 +01:00
|
|
|
|
(interactive)
|
2014-03-13 15:48:34 +01:00
|
|
|
|
(if (equal (char-syntax ?_) "_")
|
2014-02-21 19:38:49 +01:00
|
|
|
|
(progn
|
|
|
|
|
(modify-syntax-entry ?_ "w")
|
|
|
|
|
(message "_ is a not word delimiter"))
|
|
|
|
|
(modify-syntax-entry ?_ "_")
|
|
|
|
|
(message "_ is a word delimiter")))
|
2014-02-21 15:23:25 +01:00
|
|
|
|
|
2017-08-01 20:55:50 +02:00
|
|
|
|
;;; TODO: Move turn-on-* functions to 'hook-functions.el'.
|
|
|
|
|
;;; Replace useless individual comments with global comment.
|
|
|
|
|
|
2017-06-24 11:04:27 +02:00
|
|
|
|
(defun turn-on-column-number-mode ()
|
|
|
|
|
"Unconditionally turn on `column-number-mode' for the current buffer."
|
|
|
|
|
(set (make-variable-buffer-local 'column-number-mode) t))
|
2017-05-28 12:12:53 +02:00
|
|
|
|
|
2017-06-22 19:09:31 +02:00
|
|
|
|
(defun turn-on-delete-trailing-whitespace ()
|
2017-06-24 11:04:27 +02:00
|
|
|
|
"Add the `delete-trailing-whitespace' function to `before-save-hook'.
|
|
|
|
|
This does not affect .csv files."
|
2017-06-22 19:09:31 +02:00
|
|
|
|
(unless (string= (file-name-extension buffer-file-name) "csv")
|
|
|
|
|
(add-hook 'before-save-hook 'delete-trailing-whitespace nil t)))
|
|
|
|
|
|
2017-06-24 11:04:27 +02:00
|
|
|
|
(defun turn-on-fmt-before-save ()
|
|
|
|
|
"Unconditionally add the `fmt' function to `before-save-hook'."
|
|
|
|
|
(add-hook 'before-save-hook 'fmt nil t))
|
|
|
|
|
|
2017-05-28 12:03:28 +02:00
|
|
|
|
(defun turn-off-indent-tabs ()
|
|
|
|
|
"Unconditionally turn off tab indentation."
|
|
|
|
|
(setq indent-tabs-mode nil))
|
|
|
|
|
|
|
|
|
|
(defun turn-on-indent-tabs ()
|
|
|
|
|
"Unconditionally turn on tab indentation."
|
|
|
|
|
(setq indent-tabs-mode t))
|
|
|
|
|
|
2017-06-24 11:04:27 +02:00
|
|
|
|
(defun turn-off-line-number-mode ()
|
|
|
|
|
"Unconditionally turn off `line-number-mode' fur the current buffer.."
|
|
|
|
|
(set (make-variable-buffer-local 'line-number-mode) nil))
|
|
|
|
|
|
|
|
|
|
(defun turn-off-linum ()
|
|
|
|
|
"Unconditionally turn off Linum mode."
|
|
|
|
|
(linum-mode 0))
|
|
|
|
|
|
2017-05-28 14:15:51 +02:00
|
|
|
|
(defun turn-on-newline-paragraph ()
|
2017-06-18 22:25:34 +02:00
|
|
|
|
"Unconditionally make of newlines the start of a paragraph."
|
2017-05-28 14:15:51 +02:00
|
|
|
|
(set (make-local-variable 'paragraph-start) "
|
|
|
|
|
"))
|
|
|
|
|
|
2017-06-17 13:14:45 +02:00
|
|
|
|
(defun turn-off-nobreak-char-display ()
|
|
|
|
|
(set (make-local-variable 'nobreak-char-display) nil))
|
|
|
|
|
|
2017-05-28 12:03:28 +02:00
|
|
|
|
(defun turn-on-skeleton-markers ()
|
|
|
|
|
"Allow skeletons to make markers to ease field navigation."
|
|
|
|
|
(add-hook 'skeleton-end-hook 'skeleton-make-markers))
|
|
|
|
|
|
2017-06-23 15:41:22 +02:00
|
|
|
|
(defun turn-on-tab-width-to-4 ()
|
|
|
|
|
"Unconditionally set tab width to 4."
|
|
|
|
|
(setq tab-width 4))
|
|
|
|
|
|
2017-06-18 22:25:34 +02:00
|
|
|
|
(defun turn-on-tab-width-to-8 ()
|
|
|
|
|
"Unconditionally set tab width to 8."
|
|
|
|
|
(setq tab-width 8))
|
|
|
|
|
|
2014-02-21 19:38:49 +01:00
|
|
|
|
(defun unfill-paragraph ()
|
|
|
|
|
"Paragraph at point is unwrapped on one single line."
|
|
|
|
|
(interactive)
|
|
|
|
|
(let ((fill-column (point-max)))
|
|
|
|
|
(fill-paragraph nil)))
|
|
|
|
|
|
|
|
|
|
(defun unfill-region ()
|
2014-02-21 20:08:20 +01:00
|
|
|
|
"Unfill all paragraphs found in current region.
|
|
|
|
|
Each paragraph stand on its line."
|
2014-02-21 19:38:49 +01:00
|
|
|
|
(interactive)
|
|
|
|
|
(let ((fill-column (point-max)))
|
|
|
|
|
(fill-region (region-beginning) (region-end) nil)))
|
|
|
|
|
|
2014-02-13 15:56:13 +01:00
|
|
|
|
(provide 'functions)
|