2017-05-16 18:18:22 +02:00
|
|
|
;;; app/regex/autoload/regex.el
|
2017-05-16 00:48:13 +02:00
|
|
|
|
|
|
|
(defvar +regex--text-buffer nil)
|
2017-05-17 01:30:43 +02:00
|
|
|
(defvar +regex--text-replace-buffer nil)
|
2017-05-16 00:48:13 +02:00
|
|
|
(defvar +regex--expr-buffer nil)
|
2017-05-17 01:30:43 +02:00
|
|
|
(defvar +regex--expr-replace-buffer nil)
|
2017-05-16 00:48:13 +02:00
|
|
|
(defvar +regex--groups-buffer nil)
|
2017-05-17 01:30:43 +02:00
|
|
|
(defvar +regex--replace-buffer nil)
|
2017-05-16 00:48:13 +02:00
|
|
|
|
|
|
|
;;
|
|
|
|
(defface +regex-match-0-face
|
2017-05-17 01:30:43 +02:00
|
|
|
`((t (:foreground "Black" :background ,(doom-color 'magenta) :bold t)))
|
2017-05-16 18:18:22 +02:00
|
|
|
"TODO"
|
2017-05-16 00:48:13 +02:00
|
|
|
:group 'doom)
|
|
|
|
|
|
|
|
(defface +regex-match-1-face
|
2017-05-17 01:30:43 +02:00
|
|
|
`((t (:foreground "Black" :background ,(doom-color 'blue) :bold t)))
|
2017-05-16 18:18:22 +02:00
|
|
|
"TODO"
|
2017-05-16 00:48:13 +02:00
|
|
|
:group 'doom)
|
|
|
|
|
|
|
|
(defface +regex-match-2-face
|
2017-05-17 01:30:43 +02:00
|
|
|
`((t (:foreground "Black" :background ,(doom-color 'green) :bold t)))
|
2017-05-16 18:18:22 +02:00
|
|
|
"TODO"
|
2017-05-16 00:48:13 +02:00
|
|
|
:group 'doom)
|
|
|
|
|
|
|
|
(defvar +regex-faces
|
|
|
|
'(+regex-match-0-face +regex-match-1-face +regex-match-2-face)
|
|
|
|
"TODO")
|
|
|
|
|
|
|
|
;;
|
|
|
|
(defvar +regex-mode-map
|
|
|
|
(let ((map (make-sparse-keymap)))
|
2017-05-17 01:30:43 +02:00
|
|
|
(define-key map "\C-c\C-c" #'+regex-update-buffers)
|
|
|
|
(define-key map "\C-c\C-r" #'=regex/replace)
|
|
|
|
(define-key map "\C-c\C-k" #'+regex/quit)
|
|
|
|
(define-key map [remap kill-this-buffer] #'+regex/quit)
|
|
|
|
(define-key map [remap kill-buffer] #'+regex/quit)
|
2017-05-16 00:48:13 +02:00
|
|
|
map)
|
|
|
|
"TODO")
|
|
|
|
|
2017-05-16 18:18:22 +02:00
|
|
|
;;;###autoload
|
2017-05-16 00:48:13 +02:00
|
|
|
(define-minor-mode +regex-mode
|
|
|
|
"TODO"
|
|
|
|
:init-value nil
|
|
|
|
:global nil
|
|
|
|
:lighter ""
|
|
|
|
:keymap +regex-mode-map
|
|
|
|
(if +regex-mode
|
|
|
|
(add-hook 'after-change-functions #'+regex-update-buffers nil t)
|
|
|
|
(remove-hook 'after-change-functions #'+regex-update-buffers t)))
|
|
|
|
|
|
|
|
;;;###autoload
|
|
|
|
(defun =regex (&optional dummy-text)
|
|
|
|
"Start the Regex IDE."
|
|
|
|
(interactive "P")
|
2017-05-17 01:30:43 +02:00
|
|
|
(unless (buffer-live-p +regex--expr-buffer)
|
|
|
|
(condition-case ex
|
|
|
|
(progn
|
|
|
|
(setq +regex--expr-buffer (get-buffer-create "*doom-regex*")
|
|
|
|
+regex--text-buffer (if dummy-text (get-buffer-create "*doom-regex-text*") (current-buffer))
|
|
|
|
+regex--groups-buffer (get-buffer-create "*doom-regex-groups*"))
|
|
|
|
(when dummy-text
|
|
|
|
(+workspace-switch +regex-workspace-name t)
|
|
|
|
(switch-to-buffer +regex--text-buffer)
|
|
|
|
(with-current-buffer +regex--text-buffer
|
|
|
|
(insert +regex-dummy-text)))
|
2018-01-06 03:27:23 -05:00
|
|
|
(pop-to-buffer +regex--groups-buffer)
|
|
|
|
(pop-to-buffer +regex--expr-buffer)
|
2017-05-17 01:30:43 +02:00
|
|
|
(with-current-buffer +regex--expr-buffer
|
|
|
|
(conf-mode)
|
|
|
|
(rainbow-delimiters-mode +1)
|
2017-05-27 14:33:59 +02:00
|
|
|
(doom/toggle-line-numbers +1)
|
2017-05-17 01:30:43 +02:00
|
|
|
(setq-local require-final-newline nil)
|
|
|
|
(+regex-mode +1)
|
|
|
|
(text-scale-set 3)))
|
|
|
|
('error
|
|
|
|
(+regex/quit)
|
|
|
|
(error "Failed to open the Regexp IDE: %s" ex)))))
|
|
|
|
|
|
|
|
;;;###autoload
|
|
|
|
(defun =regex/replace ()
|
|
|
|
(interactive)
|
|
|
|
(unless (buffer-live-p +regex--replace-buffer)
|
|
|
|
(let (text)
|
|
|
|
(=regex t)
|
|
|
|
(with-selected-window (get-buffer-window +regex--text-buffer)
|
|
|
|
(setq text (buffer-string))
|
|
|
|
(select-window (split-window-right))
|
|
|
|
(switch-to-buffer (get-buffer-create "*doom-regex-text-repl*"))
|
|
|
|
(erase-buffer)
|
|
|
|
(insert text)
|
|
|
|
(read-only-mode +1)
|
|
|
|
(setq +regex--text-replace-buffer (current-buffer)))
|
|
|
|
(with-current-buffer +regex--expr-buffer
|
|
|
|
(select-window (split-window-right))
|
|
|
|
(switch-to-buffer (get-buffer-create "*doom-regex-repl*"))
|
|
|
|
(conf-mode)
|
|
|
|
(rainbow-delimiters-mode +1)
|
2017-05-27 14:33:59 +02:00
|
|
|
(doom/toggle-line-numbers -1)
|
2017-05-17 01:30:43 +02:00
|
|
|
(setq-local require-final-newline nil)
|
|
|
|
(setq mode-line-format nil
|
|
|
|
+regex--expr-replace-buffer (current-buffer))
|
|
|
|
(+regex-mode +1)
|
|
|
|
(text-scale-set 3)))))
|
2017-05-16 00:48:13 +02:00
|
|
|
|
|
|
|
;;;###autoload
|
|
|
|
(defun +regex/quit ()
|
|
|
|
"TODO"
|
|
|
|
(interactive)
|
|
|
|
(when (and +regex--text-buffer (buffer-live-p +regex--text-buffer))
|
|
|
|
(with-current-buffer +regex--text-buffer
|
|
|
|
(+regex-mode -1)
|
2017-05-17 01:30:43 +02:00
|
|
|
(remove-overlays nil nil 'category '+regex))
|
|
|
|
(when (equal (buffer-name +regex--text-buffer) "*doom-regex-text*")
|
|
|
|
(kill-buffer +regex--text-buffer)))
|
2017-05-16 00:48:13 +02:00
|
|
|
(when (equal (+workspace-current-name) +regex-workspace-name)
|
2017-05-17 01:30:43 +02:00
|
|
|
(+workspace/delete +regex-workspace-name))
|
|
|
|
(mapc (lambda (bufname)
|
|
|
|
(let ((buf (symbol-value bufname)))
|
|
|
|
(when (and buf (buffer-live-p buf))
|
|
|
|
(kill-buffer buf)
|
|
|
|
(set bufname nil))))
|
|
|
|
(list '+regex--text-replace-buffer
|
|
|
|
'+regex--expr-replace-buffer
|
|
|
|
'+regex--expr-buffer
|
|
|
|
'+regex--groups-buffer
|
|
|
|
'+regex--replace-buffer)))
|
|
|
|
|
|
|
|
(defun +regex--expr ()
|
|
|
|
(when (buffer-live-p +regex--expr-buffer)
|
|
|
|
(with-current-buffer +regex--expr-buffer
|
|
|
|
(string-trim (buffer-string)))))
|
|
|
|
|
|
|
|
(defun +regex--expr-replace ()
|
|
|
|
(when (buffer-live-p +regex--expr-replace-buffer)
|
|
|
|
(with-current-buffer +regex--expr-replace-buffer
|
|
|
|
(string-trim (buffer-string)))))
|
2017-05-16 00:48:13 +02:00
|
|
|
|
|
|
|
;;;###autoload
|
|
|
|
(defun +regex-update-buffers (&optional beg end len)
|
|
|
|
(interactive)
|
2017-05-17 01:30:43 +02:00
|
|
|
(let* ((inhibit-read-only t)
|
|
|
|
(regex (or (+regex--expr) ""))
|
|
|
|
(replace (or (+regex--expr-replace) ""))
|
|
|
|
(str (or (with-current-buffer +regex--text-buffer (buffer-string)) "")))
|
|
|
|
(with-current-buffer +regex--groups-buffer
|
|
|
|
(erase-buffer))
|
|
|
|
(with-current-buffer +regex--text-buffer
|
|
|
|
(remove-overlays nil nil 'category '+regex)
|
|
|
|
(when (> (length regex) 0)
|
2017-05-16 00:48:13 +02:00
|
|
|
(save-excursion
|
2017-05-17 01:30:43 +02:00
|
|
|
(goto-char (point-min))
|
|
|
|
(pcase +regex-default-backend
|
|
|
|
('emacs (+regex-backend-emacs regex replace str))
|
|
|
|
('perl (+regex-backend-perl regex replace str))))))
|
|
|
|
(with-current-buffer +regex--groups-buffer
|
|
|
|
(goto-char (point-min)))))
|
2017-05-16 00:48:13 +02:00
|
|
|
|
|
|
|
|
|
|
|
;; --- backends ---------------------------
|
|
|
|
|
2017-05-17 01:30:43 +02:00
|
|
|
(defun +regex--render-perl (regex text)
|
2017-05-16 00:48:13 +02:00
|
|
|
"From <https://github.com/jwiegley/regex-tool>"
|
|
|
|
(with-temp-buffer
|
|
|
|
(insert (format "@lines = <DATA>;
|
|
|
|
$line = join(\"\", @lines);
|
|
|
|
print \"(\";
|
2017-05-17 01:30:43 +02:00
|
|
|
while ($line =~ m/%s/gm) {
|
2017-05-16 00:48:13 +02:00
|
|
|
print \"(\", length($`), \" \", length($&), \" \";
|
|
|
|
for $i (1 .. 20) {
|
|
|
|
if ($$i) {
|
|
|
|
my $group = $$i;
|
|
|
|
$group =~ s/([\\\\\"])/\\\\\\1/g;
|
|
|
|
print \"(\", $i, \" . \\\"\", $group, \"\\\") \";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
print \")\";
|
|
|
|
}
|
|
|
|
print \")\";
|
|
|
|
__DATA__
|
2017-05-17 01:30:43 +02:00
|
|
|
%s" (replace-regexp-in-string "/" "\\/" regex nil t) text))
|
2017-05-16 00:48:13 +02:00
|
|
|
(call-process-region (point-min) (point-max) "perl" t t)
|
|
|
|
(goto-char (point-min))
|
|
|
|
(read (current-buffer))))
|
|
|
|
|
2017-05-17 01:30:43 +02:00
|
|
|
(defun +regex--replace-perl (regex replace text)
|
|
|
|
(unless (or (string-empty-p regex)
|
|
|
|
(string-empty-p replace)
|
|
|
|
(string-empty-p text))
|
|
|
|
(with-temp-buffer
|
|
|
|
(insert (format "@lines = <DATA>;
|
|
|
|
$line = join(\"\", @lines);
|
|
|
|
$line =~ s/%s/%s/gm;
|
|
|
|
print $line;
|
|
|
|
__DATA__
|
|
|
|
%s" (replace-regexp-in-string "/" "\\/" regex nil t) (replace-regexp-in-string "/" "\\/" replace nil t) text))
|
|
|
|
(call-process-region (point-min) (point-max) "perl" t t)
|
|
|
|
(buffer-string))))
|
|
|
|
|
2017-05-16 00:48:13 +02:00
|
|
|
;;;###autoload
|
2017-05-17 01:30:43 +02:00
|
|
|
(defun +regex-backend-perl (regex replace str)
|
2017-05-16 00:48:13 +02:00
|
|
|
"TODO"
|
2017-05-17 01:30:43 +02:00
|
|
|
(cl-assert (stringp regex))
|
|
|
|
(cl-assert (stringp replace))
|
|
|
|
(cl-assert (stringp str))
|
|
|
|
(let ((i 0)
|
|
|
|
(results (+regex--render-perl regex str)))
|
|
|
|
(when (buffer-live-p +regex--text-replace-buffer)
|
|
|
|
(let ((replace (+regex--replace-perl regex replace str)))
|
|
|
|
(with-current-buffer +regex--text-replace-buffer
|
|
|
|
(erase-buffer)
|
|
|
|
(insert
|
|
|
|
(if (and (listp results)
|
|
|
|
replace
|
|
|
|
(not (string-empty-p replace)))
|
|
|
|
replace
|
|
|
|
str)))))
|
|
|
|
(dolist (result (if (listp results) results))
|
|
|
|
(let* ((offset (nth 0 result))
|
|
|
|
(length (nth 1 result))
|
|
|
|
(matches (nthcdr 2 result))
|
|
|
|
(ov (make-overlay (1+ offset) (+ offset length 1))))
|
|
|
|
(overlay-put ov 'face (nth (mod i 3) +regex-faces))
|
|
|
|
(overlay-put ov 'category '+regex)
|
2017-05-16 00:48:13 +02:00
|
|
|
(cl-incf i)
|
2017-05-17 01:30:43 +02:00
|
|
|
(let* ((match-zero (buffer-substring (1+ offset) (+ offset length 1)))
|
|
|
|
(line (format "Match: %s\n" (propertize match-zero 'face 'font-lock-string-face))))
|
2017-05-16 00:48:13 +02:00
|
|
|
(with-current-buffer +regex--groups-buffer
|
2017-05-17 01:30:43 +02:00
|
|
|
(insert line)))
|
2017-05-16 00:48:13 +02:00
|
|
|
(dolist (match matches)
|
|
|
|
(with-current-buffer +regex--groups-buffer
|
|
|
|
(goto-char (point-max))
|
2017-05-17 01:30:43 +02:00
|
|
|
(insert (format "Group %d: %s\n"
|
|
|
|
(propertize (car match) 'face 'font-lock-constant-face)
|
|
|
|
(propertize (cdr match) 'face 'font-lock-string-face)))))
|
2017-05-16 00:48:13 +02:00
|
|
|
(with-current-buffer +regex--groups-buffer
|
|
|
|
(insert ?\n))))))
|
|
|
|
|
|
|
|
;;;###autoload
|
2017-05-17 01:30:43 +02:00
|
|
|
(defun +regex-backend-emacs (regex replace str)
|
2017-05-16 00:48:13 +02:00
|
|
|
"TODO"
|
2017-05-17 01:30:43 +02:00
|
|
|
(cl-assert (stringp regex))
|
|
|
|
(cl-assert (stringp replace))
|
|
|
|
(cl-assert (stringp str))
|
2017-05-16 00:48:13 +02:00
|
|
|
(let ((i 0)
|
|
|
|
pos)
|
2017-05-17 01:30:43 +02:00
|
|
|
(when (buffer-live-p +regex--text-replace-buffer)
|
|
|
|
(with-current-buffer +regex--text-replace-buffer
|
|
|
|
(erase-buffer)
|
|
|
|
(insert str)
|
|
|
|
(when (and (listp results) (string-empty-p replace))
|
|
|
|
(replace-regexp regex replace))))
|
2017-05-16 00:48:13 +02:00
|
|
|
(while (and (setq pos (point))
|
|
|
|
(re-search-forward regex nil t))
|
|
|
|
(if (= (point) pos)
|
|
|
|
(forward-char 1)
|
2017-05-17 01:30:43 +02:00
|
|
|
(let ((ov (make-overlay (match-beginning 0) (match-end 0))))
|
|
|
|
(overlay-put ov 'face (nth (mod i 3) +regex-faces))
|
|
|
|
(overlay-put ov 'category '+regex))
|
2017-05-16 00:48:13 +02:00
|
|
|
(cl-incf i)
|
|
|
|
(dotimes (i 10)
|
2017-12-10 14:49:52 -05:00
|
|
|
(when-let* ((text (match-string i)))
|
2017-05-16 00:48:13 +02:00
|
|
|
(save-match-data
|
|
|
|
(with-current-buffer +regex--groups-buffer
|
|
|
|
(goto-char (point-max))
|
2017-05-17 01:30:43 +02:00
|
|
|
(insert
|
|
|
|
(format "Group %d: %s\n"
|
|
|
|
(propertize i 'face 'font-lock-constant-face)
|
|
|
|
(propertize text 'face 'font-lock-string-face)))))))
|
2017-05-16 00:48:13 +02:00
|
|
|
(with-current-buffer +regex--groups-buffer
|
|
|
|
(insert ?\n))))))
|
|
|
|
|