From 55b1dd0e5fecb39a3d4c2eedfe173a12019020c9 Mon Sep 17 00:00:00 2001 From: Andreas Gerler Date: Mon, 13 Jan 2014 18:04:31 +0100 Subject: [PATCH] * added ido-mode * added virtual-regexp * added fixup-whitespace Signed-off-by: Andreas Gerler --- cl-lib-0.3.el | 342 ++++++++++++++ cl-lib-0.3.elc | Bin 0 -> 3881 bytes ido-vertical-mode-0.1.1.el | 232 ++++++++++ ido-vertical-mode-0.1.1.elc | Bin 0 -> 6909 bytes init.el | 36 ++ visual-regexp.el | 892 ++++++++++++++++++++++++++++++++++++ visual-regexp.elc | Bin 0 -> 24430 bytes 7 files changed, 1502 insertions(+) create mode 100644 cl-lib-0.3.el create mode 100644 cl-lib-0.3.elc create mode 100644 ido-vertical-mode-0.1.1.el create mode 100644 ido-vertical-mode-0.1.1.elc create mode 100644 visual-regexp.el create mode 100644 visual-regexp.elc diff --git a/cl-lib-0.3.el b/cl-lib-0.3.el new file mode 100644 index 00000000..a1df0a23 --- /dev/null +++ b/cl-lib-0.3.el @@ -0,0 +1,342 @@ +;;; cl-lib.el --- Properly prefixed CL functions and macros -*- coding: utf-8 -*- + +;; Copyright (C) 2012, 2013 Free Software Foundation, Inc. + +;; Author: Stefan Monnier +;; vcomment: Emacs-24.3's version is 1.0 so this has to stay below. +;; Version: 0.3 + +;; 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 . + +;;; Commentary: + +;; This is a forward compatibility package, which provides (a subset of) the +;; features of the cl-lib package introduced in Emacs-24.3, for use on +;; previous emacsen. + +;; Make sure this is installed *late* in your `load-path`, i.e. after Emacs's +;; built-in .../lisp/emacs-lisp directory, so that if/when you upgrade to +;; Emacs-24.3, the built-in version of the file will take precedence, otherwise +;; you could get into trouble (although we try to hack our way around the +;; problem in case it happens). + +;; This code is largely copied from Emacs-24.3's cl.el, with the alias bindings +;; simply reversed. + +;;; Code: + +(when (functionp 'macroexp--compiler-macro) + ;; `macroexp--compiler-macro' was introduced as part of the big CL + ;; reorganization which moved/reimplemented some of CL into core (mostly the + ;; setf and compiler-macro support), so its presence indicates we're running + ;; in an Emacs that comes with the new cl-lib.el, where this file should + ;; never be loaded! + (message "Real cl-lib shadowed by compatibility cl-lib? (%s)" load-file-name) + (when load-file-name + ;; (message "Let's try to patch things up") + (let ((loaddir (file-name-directory load-file-name)) + load-path-dir) + ;; Find the problematic directory from load-path. + (dolist (dir load-path) + (if (equal loaddir (expand-file-name (file-name-as-directory dir))) + (setq load-path-dir dir))) + (when load-path-dir + ;; (message "Let's move the offending dir to the end") + (setq load-path (append (remove load-path-dir load-path) + (list load-path-dir))) + ;; Here we could manually load cl-lib and then return immediately. + ;; But Emacs currently doesn't provide any way for a file to "return + ;; immediately", so instead we make sure the rest of the file does not + ;; throw away any pre-existing definition. + )))) + +(require 'cl) + +;; Some of Emacs-24.3's cl.el definition are not just aliases, because either +;; the feature was dropped from cl-lib.el or because the cl-lib version is +;; not fully compatible. +;; Let's just not include them here, since it is very important that if code +;; works with this cl-lib.el it should also work with Emacs-24.3's cl-lib.el, +;; whereas the reverse is much less important. + +(dolist (var '( + ;; loop-result-var + ;; loop-result + ;; loop-initially + ;; loop-finally + ;; loop-bindings + ;; loop-args + ;; bind-inits + ;; bind-block + ;; lambda-list-keywords + float-negative-epsilon + float-epsilon + least-negative-normalized-float + least-positive-normalized-float + least-negative-float + least-positive-float + most-negative-float + most-positive-float + ;; custom-print-functions + )) + (let ((new (intern (format "cl-%s" var)))) + (unless (boundp new) (defvaralias new var)))) + +(dolist (fun '( + (get* . cl-get) + (random* . cl-random) + (rem* . cl-rem) + (mod* . cl-mod) + (round* . cl-round) + (truncate* . cl-truncate) + (ceiling* . cl-ceiling) + (floor* . cl-floor) + (rassoc* . cl-rassoc) + (assoc* . cl-assoc) + (member* . cl-member) + (delete* . cl-delete) + (remove* . cl-remove) + (defsubst* . cl-defsubst) + (sort* . cl-sort) + (function* . cl-function) + (defmacro* . cl-defmacro) + (defun* . cl-defun) + (mapcar* . cl-mapcar) + + remprop + getf + tailp + list-length + nreconc + revappend + concatenate + subseq + random-state-p + make-random-state + signum + isqrt + lcm + gcd + notevery + notany + every + some + mapcon + mapcan + mapl + maplist + map + equalp + coerce + tree-equal + nsublis + sublis + nsubst-if-not + nsubst-if + nsubst + subst-if-not + subst-if + subsetp + nset-exclusive-or + set-exclusive-or + nset-difference + set-difference + nintersection + intersection + nunion + union + rassoc-if-not + rassoc-if + assoc-if-not + assoc-if + member-if-not + member-if + merge + stable-sort + search + mismatch + count-if-not + count-if + count + position-if-not + position-if + position + find-if-not + find-if + find + nsubstitute-if-not + nsubstitute-if + nsubstitute + substitute-if-not + substitute-if + substitute + delete-duplicates + remove-duplicates + delete-if-not + delete-if + remove-if-not + remove-if + replace + fill + reduce + compiler-macroexpand + define-compiler-macro + assert + check-type + typep + deftype + defstruct + callf2 + callf + letf* + letf + rotatef + shiftf + remf + psetf + (define-setf-method . define-setf-expander) + declare + the + locally + multiple-value-setq + multiple-value-bind + symbol-macrolet + macrolet + progv + psetq + do-all-symbols + do-symbols + dotimes + dolist + do* + do + loop + return-from + return + block + etypecase + typecase + ecase + case + load-time-value + eval-when + destructuring-bind + gentemp + gensym + pairlis + acons + subst + adjoin + copy-list + ldiff + list* + cddddr + cdddar + cddadr + cddaar + cdaddr + cdadar + cdaadr + cdaaar + cadddr + caddar + cadadr + cadaar + caaddr + caadar + caaadr + caaaar + cdddr + cddar + cdadr + cdaar + caddr + cadar + caadr + caaar + tenth + ninth + eighth + seventh + sixth + fifth + fourth + third + endp + rest + second + first + svref + copy-seq + evenp + oddp + minusp + plusp + floatp-safe + declaim + proclaim + nth-value + multiple-value-call + multiple-value-apply + multiple-value-list + values-list + values + pushnew + decf + incf + + dolist + dotimes + )) + (let ((new (if (consp fun) (prog1 (cdr fun) (setq fun (car fun))) + (intern (format "cl-%s" fun))))) + (unless (fboundp new) (defalias new fun)))) + +;; `cl-labels' is not 100% compatible with `labels' when using dynamic scoping +;; (mostly because it does not turn lambdas that refer to those functions into +;; closures). OTOH it is compatible when using lexical scoping. + +(unless (fboundp 'cl-labels) + (defmacro cl-labels (&rest args) + (unless (and (boundp 'lexical-binding) lexical-binding) + ;; We used to signal an error rather than a message, but in many uses of + ;; cl-labels, the value of lexical-binding doesn't actually matter. + ;; More importantly, the value of `lexical-binding' here is unreliable + ;; (it does not necessarily reflect faithfully whether the output of this + ;; macro will be interpreted as lexically bound code or not). + (message "This `cl-labels' requires `lexical-binding' to be non-nil")) + `(labels ,@args))) + +;;;; ChangeLog: + +;; 2013-05-22 Stefan Monnier +;; +;; * cl-lib.el (cl-labels): Demote error to message and improve it. +;; +;; 2012-11-30 Stefan Monnier +;; +;; * cl-lib.el: Try and patch things up in case we're hiding the real cl-lib. +;; +;; 2012-11-22 Stefan Monnier +;; +;; Add cl-letf and cl-labels. +;; +;; 2012-11-16 Stefan Monnier +;; +;; * packages/cl-lib: New package. +;; + + +(provide 'cl-lib) +;;; cl-lib.el ends here diff --git a/cl-lib-0.3.elc b/cl-lib-0.3.elc new file mode 100644 index 0000000000000000000000000000000000000000..0e3e83cd15c3e99bf37a1df9e75bb5410370d83a GIT binary patch literal 3881 zcmbtXQIF%c5%%Nl23eqJdqs<6Z`O_z0WCGRe>7a)5%+=mM>Fmq(sRkr+z8TJp$eH2z^-uqN`@+a{ zvsFGCYQ6MS?2V{YPKC{VZ^3oGAyE|gtijIWyIK0(>~x|^ng~4-yowavG8cfEF!$26?*ZxUTk zwDi6{R!-yK_!ve`gQ#>4R>tp-w)7=E3Qstvc$Ot3;_imU1X7DeI%o--h=c#Xey69W zll8ulNp1^C<5f1l!E<}DO6S>+qgA$;<5@ggjaTVn{%kKLU^$%n=a;N{mEPQr&MxoS*z?u+E@J7;=xjB9gXbO~Fnm*X z%?3U?06cn-EjkZY={3t_DV$(#^x`sl!Pb^|7QvAP#IoQv_CMuCP@FA)<|UY1 z?U;ViRul0>NVU(D7IW2`hRkE~uRt(tu&@B>Z0@zZh0?cgFiCiBL+ zJsG75hLE=hUod=2BK(1@sB4M*cCxZNiQ%Dz8rYyoiLY!DBR4R;lZmXo(x^NU?kOz= zzI6~X)>T5QUnMN_a*F)gdKHxX5B{+Jvx_2F*+WAI*q}UMQ`9izF8pLy8X99izwu-0 z>Q^Dlop5jw1zyrY;+Y2vVDw(6irFe(Q~R-h|ebRw8BpG#xEi08l>hjT{} z>ENCOCzm)zv*{Qe1svX6*P&s~nuYf^?^Oo^=poo+m8{mXUmgia7E;T>he)v2aMr!n zKm^&+w`<>T2sSE^;CSnLl&3)Ypzhu6VmxXILEUknC6JNRnvZa6fK{T-#o%=yrW}g3 zvo+yJN@|4CHHC!gE)#<&w;@Ks>0hVy;eUQl^MqX`9Taoe) z4ndk%w8;xHwvo7dkU+K(W>1muxS*k-hM6$nP6wsK3yIDnA#DWw%&l~}q{d0)3qxe! z5WHuvpr72dvvr)wDSOquuVILy5TWJtrJZ*!&(j;8V<^ zq-blcIO=>?IuDUfrn5Uxy<~^SG=z7+Yb|hEDA5{3(PDmlN5pClGKBSPoW-yb*# ziOtQoGXIb?`x*g=SIyFa;#5Wf${~U_u}tHD(%h6+;Y|+l-k^o^TU8?I;8{sEVh7D% zXOfAelFil@D42&}bWOS`&|ISvq-M+aCEMCl)#^soIRBl{Euug+51(RdoFVyrwYEB5 zh;R%^h0BsBC;DOd=Vk;lgL7(R0)Sp_9k0H2BQ8n=SXxN$`FnapzQAvJ9M~S}4caE>JQ; z>WBXNzZTtfZtFdodjOjAGE}xJ$_xBl7(^IEq(q?5YcME^NJX9qJg}IDfq9UKROH2V zBCdmc;Kg;lxlVsjA2oCeSX;lq5sE8%9IhT{=GA74!J{}b>D3e7CE^Be+d2%*R=I-E zRq*EHOHpqujyV3$@H_sm5VnB}HEXHK7Lcu!Y0=NuC~tM_GU~*OQpUJa*j8r|V3@#e zcPgKR7suSE;e|`$_i-3bAcUlkrxE8=w|;BnBbzKyAMqL@Dg@Y+%8!ji>>{{d6Kko_ zPsDa^Mwh=#{vN(uxQ(BNjvw9ie9paPwlX8`@t0@lKS5>lC1CD9=hr7c_RXh!LUGX{ zxDaH-dioA#=oZ6YyZ3|nm)Pvkym@-BkJrDX#?o5iS~CfH!!iEeu*2^teK+M@-6{Mp ZVMS_9=#D<$$nv(}-v2D~9bHdPe*@2X5sCl+ literal 0 HcmV?d00001 diff --git a/ido-vertical-mode-0.1.1.el b/ido-vertical-mode-0.1.1.el new file mode 100644 index 00000000..f7738d35 --- /dev/null +++ b/ido-vertical-mode-0.1.1.el @@ -0,0 +1,232 @@ +;;; ido-vertical-mode.el --- Makes ido-mode display vertically. + +;; Copyright (C) 2013 Steven Degutis + +;; Author: Steven Degutis +;; Maintainer: Daniel Gempesaw +;; Version: 0.1.1 +;; Keywords: convenience +;; URL: https://github.com/gempesaw/ido-vertical-mode.el + +;; 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 . + +;;; Commentary: + +;; Makes ido-mode display prospects vertically + +;;; Code: + +(require 'ido) + +(defvar ido-vertical-decorations + '("\n-> " ; left bracket around prospect list + "" ; right bracket around prospect list + "\n " ; separator between prospects, depends on `ido-separator` + "\n ..." ; inserted at the end of a truncated list of prospects + "[" ; left bracket around common match string + "]" ; right bracket around common match string + " [No match]" + " [Matched]" + " [Not readable]" + " [Too big]" + " [Confirm]" + "\n-> " ; left bracket around the sole remaining completion + "" ; right bracket around the sole remaining completion + ) + + "Changing the decorations does most of the work for ido-vertical + +This sets up newlines and arrows before, between, and after the +prospects. For additional information, see `ido-decorations'.") + +(defvar ido-vertical-old-decorations nil + "The original `ido-decorations' variable + +We need to keep track of the original value so we can restore it +when turning `ido-vertical-mode' off") + +(defvar ido-vertical-old-completions nil + "The original `ido-completions' function + +We need to keep track of the original value of `ido-completions' +so we can restore it when turning `ido-vertical-mode' off") + +(defgroup ido-vertical-mode nil + "Make ido behave vertically." + :group 'ido-mode) + +(defcustom ido-vertical-define-keys 'C-n-and-C-p-only + "Defines which keys that ido-vertical-mode redefines." + :type '(choice + (const :tag "Keep default ido keys." nil) + (const :tag "C-p and C-n are up & down in match" 'C-n-and-C-p-only) + (const :tag "C-p/up and C-n/down are up and down in match." 'C-n-C-p-up-and-down) + (const :tag "C-p/up, C-n/down are up/down in match. left or right cycle history or directory." 'C-n-C-p-up-down-left-right)) + :group 'ido-vertical-mode) + +;; borrowed from ido.el and modified to work better when vertical +(defun ido-vertical-completions (name) + ;; Return the string that is displayed after the user's text. + ;; Modified from `icomplete-completions'. + + (let* ((comps ido-matches) + (ind (and (consp (car comps)) (> (length (cdr (car comps))) 1) + ido-merged-indicator)) + first) + + (if (and ind ido-use-faces) + (put-text-property 0 1 'face 'ido-indicator ind)) + + (if (and ido-use-faces comps) + (let* ((fn (ido-name (car comps))) + (ln (length fn))) + (setq first (format "%s" fn)) + (put-text-property 0 ln 'face + (if (= (length comps) 1) + (if ido-incomplete-regexp + 'ido-incomplete-regexp + 'ido-only-match) + 'ido-first-match) + first) + (if ind (setq first (concat first ind))) + (setq comps (cons first (cdr comps))))) + + (cond ((null comps) + (cond + (ido-show-confirm-message + (or (nth 10 ido-decorations) " [Confirm]")) + (ido-directory-nonreadable + (or (nth 8 ido-decorations) " [Not readable]")) + (ido-directory-too-big + (or (nth 9 ido-decorations) " [Too big]")) + (ido-report-no-match + (nth 6 ido-decorations)) ;; [No match] + (t ""))) + (ido-incomplete-regexp + (concat " " (car comps))) + ((null (cdr comps)) ;one match + (concat (concat (nth 11 ido-decorations) ;; [ ... ] + (ido-name (car comps)) + (nth 12 ido-decorations)) + (if (not ido-use-faces) (nth 7 ido-decorations)))) ;; [Matched] + (t ;multiple matches + (let* ((items (if (> ido-max-prospects 0) (1+ ido-max-prospects) 999)) + (alternatives + (apply + #'concat + (cdr (apply + #'nconc + (mapcar + (lambda (com) + (setq com (ido-name com)) + (setq items (1- items)) + (cond + ((< items 0) ()) + ((= items 0) (list (nth 3 ido-decorations))) ; " | ..." + (t + (list (or ido-separator (nth 2 ido-decorations)) ; " | " + (let ((str (substring com 0))) + (if (and ido-use-faces + (not (string= str first)) + (ido-final-slash str)) + (put-text-property 0 (length str) 'face 'ido-subdir str)) + str))))) + comps)))))) + + (concat + ;; put in common completion item -- what you get by pressing tab + (if (and (stringp ido-common-match-string) + (> (length ido-common-match-string) (length name))) + (concat (nth 4 ido-decorations) ;; [ ... ] + (substring ido-common-match-string (length name)) + (nth 5 ido-decorations))) + ;; list all alternatives + (nth 0 ido-decorations) ;; { ... } + alternatives + (nth 1 ido-decorations))))))) + +(defun ido-vertical-disable-line-truncation () + "Prevent the newlines in the minibuffer from being truncated" + (set (make-local-variable 'truncate-lines) nil)) + +(defun turn-on-ido-vertical () + (if (and (eq nil ido-vertical-old-decorations) + (eq nil ido-vertical-old-completions)) + (progn + (setq ido-vertical-old-decorations ido-decorations) + (setq ido-vertical-old-completions (symbol-function 'ido-completions)))) + + (setq ido-decorations ido-vertical-decorations) + (fset 'ido-completions 'ido-vertical-completions) + + (add-hook 'ido-minibuffer-setup-hook 'ido-vertical-disable-line-truncation) + (add-hook 'ido-setup-hook 'ido-vertical-define-keys)) + +(defun turn-off-ido-vertical () + (setq ido-decorations ido-vertical-old-decorations) + (fset 'ido-completions ido-vertical-old-completions) + + (remove-hook 'ido-minibuffer-setup-hook 'ido-vertical-disable-line-truncation) + (remove-hook 'ido-setup-hbook 'ido-vertical-define-keys)) + +(defun ido-vertical-next-match () + "Call the correct next-match function for right key. + +This is based on: +- Different functions for completing directories and prior history. +" + (interactive) + (cond + ((and (boundp 'item) item (eq item 'file)) + (ido-next-match-dir)) + (t + (next-history-element 1)))) + +(defun ido-vertical-prev-match () + "Call the correct prev-match function for left key. + +This is based on: +- Different functions for completing directories and prior history. +" + (interactive) + (cond + ((and (boundp 'item) item (eq item 'file)) + (ido-prev-match-dir)) + (t + (previous-history-element 1)))) + +(defun ido-vertical-define-keys () ;; C-n/p is more intuitive in vertical layout + (when ido-vertical-define-keys + (define-key ido-completion-map (kbd "C-n") 'ido-next-match) + (define-key ido-completion-map (kbd "C-p") 'ido-prev-match) + (define-key ido-completion-map (kbd "M-p") 'ido-toggle-prefix)) + (when (memq ido-vertical-define-keys '(C-n-C-p-up-and-down C-n-C-p-up-down-left-right)) + (define-key ido-completion-map (kbd "") 'ido-prev-match) + (define-key ido-completion-map (kbd "") 'ido-next-match)) + (when (eq ido-vertical-define-keys 'C-n-C-p-up-down-left-right) + (define-key ido-completion-map (kbd "") 'ido-vertical-prev-match) + (define-key ido-completion-map (kbd "") 'ido-vertical-next-match))) + +;;;###autoload +(define-minor-mode ido-vertical-mode + "Makes ido-mode display vertically." + :global t + (if ido-vertical-mode + (turn-on-ido-vertical) + (turn-off-ido-vertical)) + (message "ido-vertical-mode has been %s" + (if ido-vertical-mode "enabled" "disabled"))) + +(provide 'ido-vertical-mode) +;;; ido-vertical-mode.el ends here diff --git a/ido-vertical-mode-0.1.1.elc b/ido-vertical-mode-0.1.1.elc new file mode 100644 index 0000000000000000000000000000000000000000..5b4bc1379f28bb5558b7ea0ff1ef491d7e9d2f58 GIT binary patch literal 6909 zcmc&(>vP-25tqM3^n|e!PoEiQ4b>)@8WbKR^=cBSO6qA+=jkRNM9mlk4kX4PfC8Xo zW%|eWw|f8yl5(0(+NnJ>?ykd_d93o& zX_^L8Z?1}R5kzUx_tQD02|dT}b1xy=CEGf7on!lu9LpXEo-hYc2u!p;OXq5T;^k?w z-+!&uZrbxl+b4kM}R3JT;sUBEqm8dIU_HQDb31g z9{uQ*04Vw`*?cjJ3VrLMPz41yi8qgY3R1r)^C+1XPqCX9C3!)BH!kn7kNVD0ztxRG z>Uv2)-ATGgf{Z#sE|bb+^jf>r{SzQ^71G)cb#0Tnu}Y>OZf&R6>(M7?ax%>~k!Ptt zJ3g+llUkqSHvZGqq?@rSifkP@8A7;$OIiY|@*KAqFW=1H4qbZ%L4sP!A;2}O1ruQ! zd!@>OQaB2g_(gwOtyVWz|5!x1q7JC)wf0W!BZtmsUNVJ1sGKPZl%M8Wjt~{(Hcug< zG?dNjG=D`*X7f$0mPoo#WkHLK5_KI%2@bOCJn-PUpozjE^%URoTB+oz-V555wJWZg{ zbDk{k+v`zx?+?_ck#h(+g5!e$y#S-rJOb14#;qq29ux5ut=10;{Dg6oDZNrEqcZpW zSG6>j7_Pi{p{PjdT9FSYki$EG-xQUt>zPWZT;vJMcUu)Zz!koMgJ~SBaWRSF>M2J@ z)l){pTb{!D94qkz9SRqT&%^)hDNr||wTY^A+xzGjzOQist=?zDb3#^Ke*r$unF%r6 zj5*Cy=r>!=y1$f@#&ho#I37S9)Xck5>@LNn#y3!}4I79Mbo{18CeP#jTQNS}M5j^Lg!L&_A^coUFw0p< z{*8}ti3kQmy5Z#jUeo8v#-)5A!a-P?au5-wDeGDZB(6fEn2m7+r@yX6O*P!R=ps<6 z9vN?q9ozox>G9aHhVSm|o}N7$yVmG?Jsl^%$L!$!yO_FxY-WY2fL?__=1N|o;~bfKE!X-elj*5U?51^yzK1Ct$*ip-|w{F;qSM6 z{s1HA2aFtRIkLy0TqZpjGf_Nr`=^7|KyWSyLX7m=z}|$ zxQyn5JM9m78bF*eS|#>4%#b;8&m+-Y0S+V(RM^#f2n;H%pfmRROrVSz9H zrrkSj@3(trr{8|aEIB~%V$UI#h5*c3RfsQ{t9+^gGfDy^c~D~5V^Aeud;s~G8G1gB z*y78wMQN7mb!j3nXK-UTWD)NRt_BhuWmV;j0C$q{xG*Y^N}-jRtEqaO$trstO`A+5 z_p9c%#esJfJ`Z&qUJJHIytWFrBjP}gzqU=bLkDzpbVOd3!Lz|7;gyu|7j7r>ksH9O zKog9LE#s|6_jbQy-M`Q5{DDRG4rBza2NQRBP1OB&yk?J+!*gC|ogO{nB?n7yF%%#9 z>V2`SQz$zdhs!tyn8EPIAq>oNWdfA~d#ZEwN_$!XheE z<{>SE=#YU5|5ifdeUXDD(sRkF7>w+~EMl*i(Y8dF@+=k;_%^K#mvneZ0~%78PzAt$f=Plm~qMl*D`nm$t5JGqq6HF#lmYE0fUn`L~fH=P=}TJZq~-ZN33l3;o(=~ zadHo{;TQMszRO?yM$aqqM0uf&Hk^+pm{%lV@XFGe)K{6C>0px%*{p0HEV*5UmzbKG z!>p@>S|^P%UjjF=qA)OLY5GbaR&s=KlnDRJo#oj#NsKRi;~7b_Bx|}P_cjrP;q5YD zXX1{Nn!#-G!to`8wGUu7^RpS;WYxcAc#~DRnx|K4#gqRIw;H$14U+yx zY+T(SY~*Q_E(-IfSUGasnw1SFx@JSo0;!^0B>pRwvcrB9nVdD)s~tM8h()ihh$EF1 zcwyWAn02OGV_=7BjhgUC3u>GUFJ60iw1fwKdmSG59Saz?J#v$Nepqc25*(#u<46Ui zAfv4lvz0!QaZfL;cuN;H5>or%a9~}Ehb`0T6!8uaVf321TtRMBT3l1rYnz1-T`aOo zy5Qx@pMawaR$YDJ(yKIy5)ZMlzj_DK6)_g)z@abkaET`&{T1x^zAC`c!3vPF6r>W4 z-$B3i9U4j6InC!>RK8qO3kFBy0zSk;*<1K|gytsVy!60;2Cfu)48@qrQg_a5f-CdOla@l)6xoNa;-eoyTZzVEMH6?tC}E0Ue&!W7bS^!Js{wJ_X&hO9cEnB5*QBL5z1IZNa|Fr28>O4w-mB;j2xW>FO$&(|c>U`-m-+D=n;#6MP3_gLkBqWJA`)Fjky8lEbQz+r0}| zm#aYZ+{Hxz#fYZ^J=F(?f>Rd(BfjN~K@MtED4tyhH3s8)jvWW6E$2%fxl0&EXt_Br zvj1`F6jLIRs}QGjRC4*Sz%k9vNTW^poV+H(2nC8Hd_4?pO(sYy8TTw4oP5`4SI}8j$E-#sq z*1)9~;>WHssP$#In(cg34&Y&Wi_KJuZamRL6ZA@<{>@fqk1(FUGQEORQ8KnY)?+C* zKptq;oK)#pI?` zh#N3Du3xxp;Tnd6mV_xzZiaWEHP+zsI*73b+I7~$8F|AmY%`zTN|hCDZGr(Av?jfZ K0z6^ZYyAuG33Q_X literal 0 HcmV?d00001 diff --git a/init.el b/init.el index ff7055db..e98c9983 100644 --- a/init.el +++ b/init.el @@ -27,6 +27,28 @@ load-path)) (require 'htmlize ) +(ido-mode t) +(setq ido-enable-prefix nil + ido-enable-flex-matching t + ido-case-fold nil + ido-auto-merge-work-directories-length -1 + ido-create-new-buffer 'always + ido-use-filename-at-point nil + ido-max- 10) +;; (require 'ido-vertical-mode) +;; (ido-vertical-mode) + +;; (defun sd/ido-define-keys() ;; C-n/p is more intuitive in vertical layout +;; (define-key ido-completion-map (kbd "C-n") 'ido-next-match) +;; (define-key ido-completion-map (kbd "") 'ido-next-match) +;; (define-key ido-completion-map (kbd "C-p") 'ido-prev-match) +;; (define-key ido-completion-map (kbd "") 'ido-prev-match) +;; ) + +(require 'visual-regexp) +(define-key global-map (kbd "M-&") 'vr/query-replace) +(define-key global-map (kbd "M-/") 'vr/replace) + ;; load org mode ;; See http://orgmode.org/worg/org-tutorials/orgtutorial_dto.html for details @@ -289,6 +311,18 @@ bundle " name " }") ) +;; (defun cfe-lookup-docs () +;; "Search current word from buffer in online docs." +;; (interactive) +;; (save-excursion +;; (skip-syntax-backward "w_") +;; (w3m-browse-url (lambda () +;; (skip-syntax-forward "w_") +;; (point) +;; ) +;; ))) + + ;;(defun scpload (&rest args) ;;"scp copy from pottwal" ;; (shell-command ( scp andreas@pottwal: emacstmp/)) @@ -449,6 +483,8 @@ vi style of % jumping to matching brace." (define-key global-map "\C-c\C-f" 'load-git-cfengine) (define-key global-map "\C-cb" 'cfe-insert-bundle) +(define-key global-map "\C-c\C-w" 'fixup-whitespace) + ;; NUMBERIC KEYPAD. nice number pad conveniences as extra function keys ;; (global-set-key (kbd "") 'ergoemacs-close-current-buffer) diff --git a/visual-regexp.el b/visual-regexp.el new file mode 100644 index 00000000..4a16fd1c --- /dev/null +++ b/visual-regexp.el @@ -0,0 +1,892 @@ +;;; visual-regexp.el --- A regexp/replace command for Emacs with interactive visual feedback + +;; Copyright (C) 2013 Marko Bencun + +;; Author: Marko Bencun +;; URL: https://github.com/benma/visual-regexp.el/ +;; Version: 0.5 +;; Package-Requires: ((cl-lib "0.2")) +;; Keywords: regexp, replace, visual, feedback + +;; This file is part of visual-regexp. + +;; visual-regexp 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. + +;; visual-regexp 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 visual-regexp. If not, see . + +;;; WHAT'S NEW +;; 0.5: emulate case-conversion of replace-regexp. +;; 0.4: vr/mc-mark: interface to multiple-cursors. +;; 0.3: Use the same history as the regular Emacs replace commands; +;; 0.2: Support for lisp expressions in the replace string, same as in (query-)replace-regexp +;; 0.1: initial release + +;;; Tip Jar +;; If you found this useful, please consider donating. +;; BTC: 1BxauiLGMQPb2pavkkQkuFe5CgrGMrUat2 + +;;; What's This? + +;; visual-regexp for Emacs is like `replace-regexp`, but with live visual feedback directly in the buffer. +;; While constructing the regexp in the minibuffer, you get live visual feedback for the matches, including group matches. +;; While constructing the replacement in the minibuffer, you get live visual feedback for the replacements. +;; It can be used to replace all matches in one go (like `replace-regexp`), or a decision can be made on each match (like `query-replace-regexp`). +;; Thanks to Detlev Zundel for his re-builder. + +;;; Where does visual-regexp come from? +;; +;; I was not happy with the way I used emacs' replace-regexp before. Constructing the regular expression is error prone and emacs' regular expressions are limited +;; (for example, no lookaheads, named groups, etc.). +;; Using re-builder to interactively build regular expressions was a step into the right direction, but manually copying over the regexp +;; to the minibuffer is cumbersome. +;; Using the idea of interactive feedback of re-builder, this package makes it possible to use just the minibuffer to construct (with live visual feedback) the regexp and replacement, +;; using Emacs style regular expressions, or optionally, regular expressions powered by other (mode modern) engines, for the replacement. For the latter part, see the package visual-regexp-steroids. + +;;; Installation + +;; If you are using Emacs 24, you can get visual-regexp from [melpa](http://melpa.milkbox.net/) with the package manager. +;; Add the following code to your init file. Of course you can select your own key bindings. +;; ---------------------------------------------------------- +;; (add-to-list 'load-path "folder-in-which-visual-regexp-files-are-in/") ;; if the files are not already in the load path +;; (require 'visual-regexp) +;; (define-key global-map (kbd "C-c r") 'vr/replace) +;; (define-key global-map (kbd "C-c q") 'vr/query-replace) +;; ;; if you use multiple-cursors, this is for you: +;; (define-key global-map (kbd "C-c m") 'vr/mc-mark) +;; ---------------------------------------------------------- +;; To customize, use `M-x customize-group [RET] visual-regexp`. + +;;; Code: +(unless (fboundp 'make-overlay) + (require 'overlay)) + +;; cl is used for the (loop ...) macro +(require 'cl-lib) + +;;; faces + +(defface vr/match-0 + '((((class color) (background light)) + :background "lightblue") + (((class color) (background dark)) + :background "steelblue4") + (t + :inverse-video t)) + "First face for displaying a whole match." + :group 'visual-regexp) + +(defface vr/match-1 + '((((class color) (background light)) + :background "pale turquoise") + (((class color) (background dark)) + :background "dodgerblue4") + (t + :inverse-video t)) + "Second face for displaying a whole match." + :group 'visual-regexp) + +(defface vr/group-0 + '((((class color) (background light)) + :background "aquamarine") + (((class color) (background dark)) + :background "blue3") + (t + :inverse-video t)) + "First face for displaying a matching group." + :group 'visual-regexp) + +(defface vr/group-1 + '((((class color) (background light)) + :background "springgreen") + (((class color) (background dark)) + :background "chartreuse4") + (t + :inverse-video t)) + "Second face for displaying a matching group." + :group 'visual-regexp) + +(defface vr/group-2 + '((((min-colors 88) (class color) (background light)) + :background "yellow1") + (((class color) (background light)) + :background "yellow") + (((class color) (background dark)) + :background "sienna4") + (t + :inverse-video t)) + "Third face for displaying a matching group." + :group 'visual-regexp) + +;;; variables + +(defcustom vr/auto-show-help t + "Show help message automatically when the minibuffer is entered." + :type 'boolean + :group 'visual-regexp) + +(defcustom vr/default-feedback-limit 50 + "Limit number of matches shown in visual feedback. +If nil, don't limit the number of matches shown in visual feedback." + :type 'integer + :group 'visual-regexp) + +(defcustom vr/default-replace-preview nil + "Preview of replacement activated by default? If activated, the original is not shown alongside the replacement." + :type 'boolean + :group 'visual-regexp) + +(defcustom vr/query-replace-from-history-variable query-replace-from-history-variable + "History list to use for the FROM argument. The default is to use the same history as Emacs' query-replace commands." + :type 'symbol + :group 'visual-regexp) + +(defcustom vr/query-replace-to-history-variable query-replace-to-history-variable + "History list to use for the TO argument. The default is to use the same history as Emacs' query-replace commands." + :type 'symbol + :group 'visual-regexp) + +(defvar vr/initialize-hook nil + "Hook called before vr/replace and vr/query-replace") + +;;; private variables + +(defconst vr--match-faces '(vr/match-0 vr/match-1) + "Faces in list for convenience") + +(defconst vr--group-faces '(vr/group-0 vr/group-1 vr/group-2) + "Faces in list for convenience") + +(defconst vr--overlay-priority 1001 + "Starting priority of visual-regexp overlays.") + +(defvar vr--in-minibuffer nil + "Is visual-regexp currently being used?") + +(defvar vr--last-minibuffer-contents nil + "Keeping track of minibuffer changes") + +(defvar vr--target-buffer-start nil + "Starting position in target buffer.") + +(defvar vr--target-buffer-end nil + "Ending position in target buffer.") + +(defvar vr--regexp-string nil + "Entered regexp.") + +(defvar vr--replace-string nil + "Entered replacement.") + +(defvar vr--feedback-limit nil + "Feedback limit currently in use.") + +(defvar vr--replace-preview nil + "Preview of replacement activated?") + +(defvar vr--target-buffer nil + "Buffer to which visual-regexp is applied to.") + +(defvar vr--overlays (make-hash-table :test 'equal) + "Overlays used in target buffer.") + +(defvar vr--visible-overlays (list) + "Overlays currently visible.") + +(defvar vr--minibuffer-message-overlay nil) + +;;; keymap + +(defvar vr/minibuffer-regexp-keymap + (let ((map (copy-keymap minibuffer-local-map))) + (define-key map (kbd "C-c ?") 'vr--minibuffer-help) + + (define-key map (kbd "C-c a") 'vr--shortcut-toggle-limit) + map) + "Keymap used while using visual-regexp,") + +(defvar vr/minibuffer-replace-keymap + (let ((map (copy-keymap minibuffer-local-map))) + (define-key map (kbd "C-c ?") 'vr--minibuffer-help) + (define-key map (kbd "C-c m") 'vr--shortcut-show-matches) + (define-key map (kbd "C-c p") 'vr--shortcut-toggle-preview) + + (define-key map (kbd "C-c a") 'vr--shortcut-toggle-limit) + map) + "Keymap used while using visual-regexp,") + +;;; helper functions + +(defun vr--shortcut-show-matches () + (interactive) + (vr--delete-overlay-displays) + ;; wait for any input to redisplay replacements + (sit-for 100000000 t) + (vr--do-replace-feedback)) + +(defun vr--shortcut-toggle-preview () + (interactive) + (setq vr--replace-preview (not vr--replace-preview)) + (vr--update-minibuffer-prompt) + (vr--do-replace-feedback)) + +(defun vr--shortcut-toggle-limit () + "Toggle the limit of overlays shown (default limit / no limit)" + (interactive) + (if vr--feedback-limit + (setq vr--feedback-limit nil) + (setq vr--feedback-limit vr/default-feedback-limit)) + (cond ((equal vr--in-minibuffer 'vr--minibuffer-regexp) + (vr--feedback)) + ((equal vr--in-minibuffer 'vr--minibuffer-replace) + (vr--feedback t) ;; update overlays + (vr--do-replace-feedback)))) + + +(defun vr--get-regexp-string () + (concat (if (equal vr--in-minibuffer 'vr--minibuffer-regexp) + (minibuffer-contents-no-properties) + vr--regexp-string))) + +(defun vr--format-error (err) + (if (eq (car err) 'error) + (car (cdr err)) + (format "%s" err))) + +;;; minibuffer functions + +(defun vr--minibuffer-set-prompt (prompt) + "Updates minibuffer prompt. Call when minibuffer is active." + (let ((inhibit-read-only t)) + (put-text-property (point-min) (minibuffer-prompt-end) 'display prompt))) + +(defun vr--set-minibuffer-prompt-regexp () + ;; (format "Regexp: %s" (vr--get-regexp-modifiers-prefix)) + "Regexp: " + ) + +(defun vr--set-minibuffer-prompt-replace () + (concat "Replace" + (let ((flag-infos (mapconcat 'identity + (delq nil (list (when vr--replace-preview "preview"))) + ", "))) + (when (not (string= "" flag-infos )) + (format " (%s)" flag-infos))) + (format " (%s)" (vr--get-regexp-string)) + ": ")) + +(defun vr--update-minibuffer-prompt () + (when (and vr--in-minibuffer (minibufferp)) + (vr--minibuffer-set-prompt + (cond ((equal vr--in-minibuffer 'vr--minibuffer-regexp) + (vr--set-minibuffer-prompt-regexp)) + ((equal vr--in-minibuffer 'vr--minibuffer-replace) + (vr--set-minibuffer-prompt-replace)))))) + + +(defun vr--minibuffer-message (message &rest args) + "Adaptation of minibuffer-message that does not use sit-for +to make the message disappear. The problem with this was that during sit-for, + the cursor was shown at the beginning of the message regardless of whether + the point was actually there or not. Workaround: we let the message stay +visible all the time in the minibuffer." + (if (not (and vr--in-minibuffer (minibufferp (current-buffer)))) + ;; fallback + (apply 'minibuffer-message message args) + ;; Clear out any old echo-area message to make way for our new thing. + (message nil) + (setq message (concat " [" message "]")) + (when args (setq message (apply 'format message args))) + (unless (zerop (length message)) + ;; The current C cursor code doesn't know to use the overlay's + ;; marker's stickiness to figure out whether to place the cursor + ;; before or after the string, so let's spoon-feed it the pos. + (put-text-property 0 1 'cursor t message)) + (unless (overlayp vr--minibuffer-message-overlay) + (setq vr--minibuffer-message-overlay (make-overlay (point-max) (point-max) nil t t))) + (move-overlay vr--minibuffer-message-overlay (point-max) (point-max)) + (overlay-put vr--minibuffer-message-overlay 'after-string message))) + +(defun vr/minibuffer-help-regexp () + (vr--minibuffer-message (format (substitute-command-keys "\\\\[vr--minibuffer-help]: helps \\[vr--shortcut-toggle-limit]: toggle show all")))) + +(defun vr/minibuffer-help-replace () + (vr--minibuffer-message (format (substitute-command-keys "\\\\[vr--minibuffer-help]: help \\[vr--shortcut-show-matches]: show matches/groups, \\[vr--shortcut-toggle-preview]: toggle preview, \\[vr--shortcut-toggle-limit]: toggle show all")))) + +(defun vr--minibuffer-help () + (interactive) + (cond ((equal vr--in-minibuffer 'vr--minibuffer-regexp) + (vr/minibuffer-help-regexp)) + ((equal vr--in-minibuffer 'vr--minibuffer-replace) + (vr/minibuffer-help-replace)))) + +;;; overlay functions + +(defun vr--get-overlay (i j) + "i: match index, j: submatch index" + (let (overlay) + (setq overlay (gethash (list i j) vr--overlays)) + (unless overlay ;; create new one if overlay does not exist yet + (setq overlay (make-overlay 0 0)) + (if (= 0 j) + (overlay-put overlay 'face (nth (mod i (length vr--match-faces)) vr--match-faces)) + (overlay-put overlay 'face (nth (mod j (length vr--group-faces)) vr--group-faces))) + (overlay-put overlay 'priority (+ vr--overlay-priority (if (= j 0) 0 1))) + (overlay-put overlay 'vr-ij (list i j)) + (puthash (list i j) overlay vr--overlays)) + overlay)) + +(defun vr--delete-overlays () + "Delete all visible overlays." + (mapc (lambda (overlay) + (delete-overlay overlay)) + vr--visible-overlays) + (setq vr--visible-overlays (list))) + +(defun vr--delete-overlay-display (overlay) + (overlay-put overlay 'display nil) + (overlay-put overlay 'after-string nil) + (overlay-put overlay 'priority vr--overlay-priority)) + +(defun vr--delete-overlay-displays () + "Delete the display of all visible overlays. Call before vr--delete-overlays." + (mapc (lambda (overlay) + (cl-multiple-value-bind (i j) (overlay-get overlay 'vr-ij) + (when (= 0 j) + (vr--delete-overlay-display overlay)))) + vr--visible-overlays)) + +;;; hooks + +(defun vr--update (beg end len) + (when (and vr--in-minibuffer (minibufferp)) + ;; minibuffer-up temporarily deletes minibuffer contents before inserting new one. + ;; don't do anything then as the messages shown by visual-regexp are irritating while browsing the history. + (unless (and (string= "" (minibuffer-contents-no-properties)) + (equal last-command 'previous-history-element)) + ;; do something when minibuffer contents changes + (unless (string= vr--last-minibuffer-contents (minibuffer-contents-no-properties)) + (setq vr--last-minibuffer-contents (minibuffer-contents-no-properties)) + ;; minibuffer contents has changed, update visual feedback. + ;; not using after-change-hook because this hook applies to the whole minibuffer, including minibuffer-messages + ;; that disappear after a while. + (cond ((equal vr--in-minibuffer 'vr--minibuffer-regexp) + (vr--feedback)) + ((equal vr--in-minibuffer 'vr--minibuffer-replace) + (vr--do-replace-feedback))))))) +(add-hook 'after-change-functions 'vr--update) + +(defun vr--minibuffer-setup () + "Setup prompt and help when entering minibuffer." + (when vr--in-minibuffer + (progn + (vr--update-minibuffer-prompt) + (when vr/auto-show-help (vr--minibuffer-help))))) +(add-hook 'minibuffer-setup-hook 'vr--minibuffer-setup) + +;;; helper functions + +(defun vr--target-window () + (if vr--target-buffer + (get-buffer-window vr--target-buffer) + nil)) + +(defun vr--compose-messages (&rest msgs) + (mapconcat 'identity (delq nil (mapcar (lambda (msg) (if (or (not msg) (string= "" msg)) nil msg)) msgs)) " - ")) + +;;; show feedback functions +(defun vr--feedback-function (forward feedback-limit callback) + "Feedback function for emacs-style regexp search" + (let ((message-line "") + (err)) + (with-current-buffer vr--target-buffer + (save-excursion + (goto-char (if forward vr--target-buffer-start vr--target-buffer-end)) + (let ((i 0) + (looping t)) + (while (and looping + (condition-case err + (if forward + (re-search-forward regexp-string vr--target-buffer-end t) + (re-search-backward regexp-string vr--target-buffer-start t)) + ('invalid-regexp (progn (setq message-line (car (cdr err))) nil)))) + (when (or (not feedback-limit) (< i feedback-limit)) ;; let outer loop finish so we can get the matches count + (cl-loop for (start end) on (match-data) by 'cddr + for j from 0 do + (funcall callback i j start end))) + (when (= (match-beginning 0) (match-end 0)) + (cond ;; don't get stuck on zero-width matches + ((and forward (> vr--target-buffer-end (point))) (forward-char)) + ((and (not forward) (< vr--target-buffer-start (point))) (backward-char)) + (t (setq looping nil)))) + (setq i (1+ i))) + (setq message-line (format "%s matches" i))))) + message-line)) + +(defun vr--feedback-match-callback (i j begin end) + (with-current-buffer vr--target-buffer + (save-excursion + (when (= 0 i) ;; make first match visible + (with-selected-window (vr--target-window) + (goto-char end))) + (let ((overlay (vr--get-overlay i j))) + (move-overlay overlay begin end vr--target-buffer) + (if (and (= 0 j) (= begin end)) ;; empty match; indicate by a pipe + (overlay-put overlay 'after-string (propertize "|" 'face (nth (mod i (length vr--match-faces)) vr--match-faces) 'help-echo "empty match")) + (overlay-put overlay 'after-string nil)) + (setq vr--visible-overlays (cons overlay vr--visible-overlays))) + ;; mark if we have reached the specified feedback limit + (when (and vr--feedback-limit (= vr--feedback-limit (1+ i)) ) + (setq limit-reached t))))) + +(defun vr--feedback (&optional inhibit-message) + "Show visual feedback for matches." + (vr--delete-overlays) + (let ((limit-reached nil) + message-line) + (setq message-line + (let ((regexp-string (vr--get-regexp-string))) + (vr--feedback-function t vr--feedback-limit 'vr--feedback-match-callback))) + (unless inhibit-message + (let ((msg (vr--compose-messages message-line (when limit-reached (format "%s matches shown, hit C-c a to show all" vr--feedback-limit))))) + (unless (string= "" msg) + (vr--minibuffer-message msg)))))) + +(defun vr--get-replacement (replacement match-data i) + (with-current-buffer vr--target-buffer + (set-match-data match-data) + (let* + ;; emulate case-conversion of (perform-replace) + ((case-fold-search (if (and case-fold-search search-upper-case) + (isearch-no-upper-case-p (vr--get-regexp-string) t) + case-fold-search)) + (nocasify (not (and case-replace case-fold-search)))) + (if (stringp replacement) + (match-substitute-replacement replacement nocasify) + (match-substitute-replacement (funcall (car replacement) (cdr replacement) i) nocasify))))) + +(defun vr--do-replace-feedback-match-callback (replacement match-data i) + (let ((begin (cl-first match-data)) + (end (cl-second match-data)) + (replacement (vr--get-replacement replacement match-data i))) + (let* ((overlay (vr--get-overlay i 0)) + (empty-match (= begin end))) + (move-overlay overlay begin end vr--target-buffer) + (vr--delete-overlay-display overlay) + (if (or empty-match vr--replace-preview) + (progn + (overlay-put overlay (if empty-match 'after-string 'display) (propertize replacement 'face (nth (mod i (length vr--match-faces)) vr--match-faces))) + (overlay-put overlay 'priority (+ vr--overlay-priority 2))) + (progn + (overlay-put overlay 'after-string + (propertize (format " => %s" replacement) 'face (nth (mod i (length vr--match-faces)) vr--match-faces))) + (overlay-put overlay 'priority (+ vr--overlay-priority 0))))))) + +(defun vr--get-replacements (feedback feedback-limit) + "Get replacements using emacs-style regexp." + (let ((regexp-string (vr--get-regexp-string)) + (message-line "") + (replacements (list)) + (err) + (buffer-contents (with-current-buffer vr--target-buffer + (buffer-substring-no-properties (point-min) (point-max))))) + (with-current-buffer vr--target-buffer + (goto-char vr--target-buffer-start) + (let ((i 0) + (looping t) + (limit-reached nil)) + (while (and + looping + (condition-case err + (re-search-forward regexp-string vr--target-buffer-end t) + ('invalid-regexp (progn (setq message-line (car (cdr err))) nil)))) + (condition-case err + (progn + (if (or (not feedback) (not feedback-limit) (< i feedback-limit)) + (setq replacements (cons + (let ((match-data (mapcar 'marker-position (match-data)))) + (list (query-replace-compile-replacement replace-string t) match-data i)) + replacements)) + (setq limit-reached t)) + (when (= (match-beginning 0) (match-end 0)) + (if (> vr--target-buffer-end (point)) + (forward-char) ;; don't get stuck on zero-width matches + (setq looping nil))) + (setq i (1+ i))) + ('error (progn + (setq message-line (vr--format-error err)) + (setq replacements (list)) + (setq looping nil))))) + (if (string= "" message-line) + (if feedback + (setq message-line (vr--compose-messages (format "%s matches" i) (when limit-reached (format "%s matches shown, hit C-c a to show all" feedback-limit)))) + (setq message-line (format "replaced %d matches" i)))))) + (list replacements message-line))) + +(defun vr--do-replace-feedback () + "Show visual feedback for replacements." + (vr--feedback t) ;; only really needed when regexp has not been changed from default (=> no overlays have been created) + (let ((replace-string (minibuffer-contents-no-properties))) + (cl-multiple-value-bind (replacements message-line) (vr--get-replacements t vr--feedback-limit) + ;; visual feedback for matches + (condition-case err + (mapc (lambda (replacement-info) (apply 'vr--do-replace-feedback-match-callback replacement-info)) replacements) + ('error (setq message-line (vr--format-error err)))) + (unless (string= "" message-line) + (vr--minibuffer-message message-line))))) + +;;; vr/replace + +(defun vr--do-replace (&optional silent) + "Replace matches." + (vr--delete-overlay-displays) + (vr--delete-overlays) + (let ((replace-string vr--replace-string)) + (cl-multiple-value-bind (replacements message-line) (vr--get-replacements nil nil) + (let ((replace-count 0) + (cumulative-offset 0) + last-match-data) + (cl-loop for replacement-info in replacements + for counter from 0 do + (setq replace-count (1+ replace-count)) + (cl-multiple-value-bind (replacement match-data i) replacement-info + ;; replace match + (let* ((replacement (vr--get-replacement replacement match-data i)) + (begin (cl-first match-data)) + (end (cl-second match-data))) + (with-current-buffer vr--target-buffer + (save-excursion + ;; first insert, then delete + ;; this ensures that if we had an active region before, the replaced match is still part of the region + (goto-char begin) + (insert replacement) + (setq cumulative-offset (+ cumulative-offset (- (point) end))) + (delete-char (- end begin)))) + (when (= 0 counter) + (setq last-match-data match-data)) + ))) + (unless (or silent (string= "" message-line)) + (vr--minibuffer-message message-line)) + ;; needed to correctly position the mark after query replace (finished with 'automatic ('!')) + (set-match-data (mapcar (lambda (el) (+ cumulative-offset el)) last-match-data)) + replace-count)))) + +(defun vr--interactive-get-args (mode) + "Get interactive args for the vr/replace and vr/query-replace functions." + (unwind-protect + (progn + (let ((buffer-read-only t)) ;; make target buffer + (when vr--in-minibuffer (error "visual-regexp already in use.")) + (setq vr--target-buffer (current-buffer)) + (setq vr--target-buffer-start (if (region-active-p) + (region-beginning) + (point))) + (setq vr--target-buffer-end (if (region-active-p) + (region-end) + (point-max))) + + (run-hooks 'vr/initialize-hook) + (setq vr--feedback-limit vr/default-feedback-limit) + + (setq vr--replace-preview vr/default-replace-preview) + + (save-excursion + ;; deactivate mark so that we can see our faces instead of region-face. + (deactivate-mark) + (progn + (setq vr--in-minibuffer 'vr--minibuffer-regexp) + (setq vr--last-minibuffer-contents "") + (setq vr--regexp-string + (read-from-minibuffer + " " ;; prompt will be set in vr--minibuffer-setup + nil vr/minibuffer-regexp-keymap + nil vr/query-replace-from-history-variable)) + ;;(setq vr--regexp-string (format "%s%s" (vr--get-regexp-modifiers-prefix) vr--regexp-string)) + + (when (equal mode 'vr--mode-regexp-replace) + (setq vr--in-minibuffer 'vr--minibuffer-replace) + (setq vr--last-minibuffer-contents "") + (setq vr--replace-string + (read-from-minibuffer + " " ;; prompt will be set in vr--minibuffer-setup + nil vr/minibuffer-replace-keymap + nil vr/query-replace-to-history-variable))))) + ;; Successfully got the args, deactivate mark now. If the command was aborted (C-g), the mark (region) would remain active. + (deactivate-mark) + (cond ((equal mode 'vr--mode-regexp-replace) + (list vr--regexp-string + vr--replace-string + vr--target-buffer-start + vr--target-buffer-end)) + ((equal mode 'vr--mode-regexp) + (list vr--regexp-string + vr--target-buffer-start + vr--target-buffer-end))))) + (progn ;; execute on finish + (setq vr--in-minibuffer nil) + (unless (overlayp vr--minibuffer-message-overlay) + (delete-overlay vr--minibuffer-message-overlay)) + (vr--delete-overlay-displays) + (vr--delete-overlays)))) + +(add-hook 'multiple-cursors-mode-enabled-hook + ;; run vr/mc-mark once per cursor by default (do not ask the user) + (lambda () + (when (boundp 'mc--default-cmds-to-run-once) + (add-to-list 'mc--default-cmds-to-run-once 'vr/mc-mark)))) + +;;;###autoload +(defun vr/mc-mark (regexp start end) + "Convert regexp selection to multiple cursors." + (interactive + (vr--interactive-get-args 'vr--mode-regexp)) + (with-current-buffer vr--target-buffer + (mc/remove-fake-cursors) + (activate-mark) + (let ((regexp-string (vr--get-regexp-string)) + ;; disable deactivating of mark after buffer-editing commands + ;; (which happens for example in visual-regexp-steroids/vr--parse-matches + ;; during the callback). + (deactivate-mark nil) + (first-fake-cursor nil)) + (vr--feedback-function t nil (lambda (i j begin end) + (with-current-buffer vr--target-buffer + (goto-char end) + (push-mark begin) + ;; temporarily enable transient mark mode + (activate-mark) + (let ((fc (mc/create-fake-cursor-at-point))) + (unless first-fake-cursor + (setq first-fake-cursor fc)))))) + + ;; one fake cursor too many, replace first one with + ;; the regular cursor. + (when first-fake-cursor + (mc/pop-state-from-overlay first-fake-cursor))) + (mc/maybe-multiple-cursors-mode))) + +;;;###autoload +(defun vr/replace (regexp replace start end) + "Regexp-replace with live visual feedback." + (interactive + (vr--interactive-get-args 'vr--mode-regexp-replace)) + (unwind-protect + (progn + (when vr--in-minibuffer (error "visual-regexp already in use.")) + (setq vr--target-buffer (current-buffer) + vr--target-buffer-start start + vr--target-buffer-end end + vr--regexp-string regexp + vr--replace-string replace) + ;; do replacement + (vr--do-replace)) + ;; execute on finish + (setq vr--in-minibuffer nil))) + +;; query-replace-regexp starts here + +(defvar vr--query-replacements nil) +;; we redefine the help text from replace.el to remove the commands we don't support. + +(defconst vr--query-replace-help + "Type Space or `y' to replace one match, Delete or `n' to skip to next, +RET or `q' to exit, Period to replace one match and exit, +Comma to replace but not move point immediately, +p to preview the replacement (like 'C-c p' during construction of the regexp), +C-r [not supported in visual-regexp], +C-w [not supported in visual-regexp], +C-l to clear the screen, redisplay, and offer same replacement again, +! to replace all remaining matches with no more questions, +^ [not supported in visual-regexp], +E [not supported in visual-regexp]" + "Help message while in `vr/query-replace'.") + +(defvar vr--query-replace-map + (let ((map (make-sparse-keymap))) + (set-keymap-parent map query-replace-map) + ;; the following replace.el commands are not supported by visual-regexp. + (define-key map "e" nil) + (define-key map "E" nil) + (define-key map "\C-r" nil) + (define-key map "\C-w" nil) + (define-key map "^" nil) + (define-key map "p" 'toggle-preview) + map + )) + +;;;###autoload +(defun vr/query-replace (regexp replace start end) + "Use vr/query-replace like you would use query-replace-regexp." + (interactive + (vr--interactive-get-args 'vr--mode-regexp-replace)) + (unwind-protect + (progn + (when vr--in-minibuffer (error "visual-regexp already in use.")) + (setq vr--target-buffer (current-buffer) + vr--target-buffer-start start + vr--target-buffer-end end + vr--regexp-string regexp + vr--replace-string replace) + (let ((replace-string vr--replace-string)) + (setq vr--query-replacements (nreverse (car (vr--get-replacements nil nil))))) + (vr--perform-query-replace regexp nil)) + ;; execute on finish + (setq vr--in-minibuffer nil))) + +(defun vr--perform-query-replace (from-string &optional map) + ;; This function is a heavily modified version of (perform-replace) from replace.el. + ;; The original plan was to use the original perform-replace, but various issues stood in the way. + (or map (setq map vr--query-replace-map)) + (and minibuffer-auto-raise + (raise-frame (window-frame (minibuffer-window)))) + (let* ((next-replacement nil) ;; replacement string for current match + (keep-going t) + (replace-count 0) + ;; a match can be replaced by a longer/shorter replacement. cumulate the difference + (cumulative-offset 0) + (recenter-last-op nil) ; Start cycling order with initial position. + (message + (apply 'propertize + (substitute-command-keys + "Query replacing %s with %s: (\\\\[help] for help) ") + minibuffer-prompt-properties))) + + ;; show visual feedback for all matches + (mapc (lambda (replacement-info) + (cl-multiple-value-bind (replacement match-data i) replacement-info + (vr--feedback-match-callback i 0 (cl-first match-data) (cl-second match-data)))) + vr--query-replacements) + + (goto-char vr--target-buffer-start) + (push-mark) + (undo-boundary) + (unwind-protect + ;; Loop finding occurrences that perhaps should be replaced. + (while (and keep-going vr--query-replacements) + ;; Advance replacement list + (cl-multiple-value-bind (replacement match-data i) (car vr--query-replacements) + (setq match-data (mapcar (lambda (el) (+ cumulative-offset el)) match-data)) + (let ((begin (cl-first match-data)) + (end (cl-second match-data))) + (setq next-replacement-orig replacement) + (setq next-replacement (vr--get-replacement replacement match-data replace-count)) + (goto-char begin) + (setq vr--query-replacements (cdr vr--query-replacements)) + + ;; default for new occurrence: no preview + (setq vr--replace-preview nil) + + (undo-boundary) + (let (done replaced key def) + ;; Loop reading commands until one of them sets done, + ;; which means it has finished handling this + ;; occurrence. + (while (not done) + ;; show replacement feedback for current occurrence + (unless replaced + (vr--do-replace-feedback-match-callback next-replacement-orig match-data i)) + ;; Bind message-log-max so we don't fill up the message log + ;; with a bunch of identical messages. + (let ((message-log-max nil)) + (message message from-string next-replacement)) + (setq key (read-event)) + (setq key (vector key)) + (setq def (lookup-key map key)) + + ;; can use replace-match afterwards + (set-match-data match-data) + + ;; Restore the match data while we process the command. + (cond ((eq def 'help) + (with-output-to-temp-buffer "*Help*" + (princ + (concat "Query replacing visual-regexp " + from-string " with " + next-replacement ".\n\n" + (substitute-command-keys + vr--query-replace-help))) + (with-current-buffer standard-output + (help-mode)))) + ((eq def 'exit) + (setq keep-going nil + done t)) + ((eq def 'act) + (unless replaced + (replace-match next-replacement t t) + (setq replace-count (1+ replace-count))) + (setq done t + replaced t)) + ((eq def 'act-and-exit) + (unless replaced + (replace-match next-replacement t t) + (setq replace-count (1+ replace-count))) + (setq keep-going nil + done t + replaced t)) + ((eq def 'act-and-show) + (unless replaced + (replace-match next-replacement t t) + (setq replace-count (1+ replace-count)) + (setq replaced t))) + ((eq def 'toggle-preview) + (setq vr--replace-preview (not vr--replace-preview))) + ((eq def 'automatic) + (setq vr--target-buffer-start (match-beginning 0) + vr--target-buffer-end (+ cumulative-offset vr--target-buffer-end)) + (setq replace-count (+ replace-count (vr--do-replace t))) + (setq done t + replaced t + keep-going nil)) + ((eq def 'skip) + (setq done t)) + ((eq def 'recenter) + ;; `this-command' has the value `query-replace', + ;; so we need to bind it to `recenter-top-bottom' + ;; to allow it to detect a sequence of `C-l'. + (let ((this-command 'recenter-top-bottom) + (last-command 'recenter-top-bottom)) + (recenter-top-bottom))) + (t + (setq this-command 'mode-exited) + (setq keep-going nil) + (setq unread-command-events + (append (listify-key-sequence key) + unread-command-events)) + (setq done t))) + (when replaced + (setq cumulative-offset (+ cumulative-offset (- (length next-replacement) (- end begin))))) + (unless (eq def 'recenter) + ;; Reset recenter cycling order to initial position. + (setq recenter-last-op nil)) + ;; in case of 'act-and-show: delete overlay display or it will still be + ;; visible even though the replacement has been made + (when replaced (vr--delete-overlay-display (vr--get-overlay i 0))))) + + ;; occurrence has been handled + ;; delete feedback overlay + (delete-overlay (vr--get-overlay i 0))))) + + ;; unwind + (progn + (vr--delete-overlay-displays) + (vr--delete-overlays) + ;; (replace-dehighlight) + )) + (unless unread-command-events + ;; point is set to the end of the last occurrence. + (goto-char (match-end 0)) + (message "Replaced %d occurrence%s" + replace-count + (if (= replace-count 1) "" "s"))))) + +(provide 'visual-regexp) + +;;; visual-regexp.el ends here diff --git a/visual-regexp.elc b/visual-regexp.elc new file mode 100644 index 0000000000000000000000000000000000000000..8bb8e7ed5f27ef1555a71c1bb05a020fd616bca5 GIT binary patch literal 24430 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 literal 0 HcmV?d00001 -- 2.47.3