app/regex: replace support & polish perl backend

Also, updated the TODO. app/regex is still a heavy WIP.
This commit is contained in:
Henrik Lissner 2017-05-17 01:30:43 +02:00
parent 8a08d0ab87
commit 374d5e0504
3 changed files with 179 additions and 81 deletions

View file

@ -89,7 +89,7 @@
+ [ ] twitter + [ ] twitter
+ [ ] present + [ ] present
** 2.0.3 [22/42] ** 2.0.3 [23/46]
+ [ ] Test ~package-autoremove~ + [ ] Test ~package-autoremove~
+ [ ] tools/upload: add ~+upload/open-remote-file~ command to open current file + [ ] tools/upload: add ~+upload/open-remote-file~ command to open current file
on the remote (with TRAMP) on the remote (with TRAMP)
@ -104,16 +104,21 @@
+ [ ] Write ~describe-setting~ for ~def-setting!~ definitions. + [ ] Write ~describe-setting~ for ~def-setting!~ definitions.
+ [ ] Fix invisible buffer-info segment in modeline for terminal Emacs + [ ] Fix invisible buffer-info segment in modeline for terminal Emacs
+ [ ] ui/doom-modeline: fix ~0/0~ display in modeline (leftover anzu state) + [ ] ui/doom-modeline: fix ~0/0~ display in modeline (leftover anzu state)
+ [1/9] New module :: tools/regex (PCRE IDE) + [2/13] New module :: tools/regex (PCRE IDE)
+ [X] perl backend + [X] perl backend
+ [ ] replace support + [X] replace support
+ [ ] export to code support + [-] highlight replaced segments
+ [0/7] export-to-code feature
+ [ ] search+replace support
+ [ ] python exporter (use ~re~ or ~regex~) + [ ] python exporter (use ~re~ or ~regex~)
+ [ ] php exporter (~preg_(match(_all)?|replace)~) + [ ] php exporter (~preg_(match(_all)?|replace)~)
+ [ ] ruby backend (~%r[.+]~) + [ ] ruby exporter (~%r[.+]~)
+ [ ] javascript (node) backend (~/.+/~) + [ ] javascript (node) exporter (~/.+/.test(...)~)
+ [ ] C exporter (~regex.h~ + ~regcomp~)
+ [ ] C++ exporter (~regex reg(regexp, ...)~)
+ [ ] syntax highlighter for ~+regex-mode~ (plus make it a major mode) + [ ] syntax highlighter for ~+regex-mode~ (plus make it a major mode)
+ [ ] README.org + [ ] README.org
+ [ ] Use ~make-process~ daemon approach rather than ~call-process~
+ [X] ui/doom: fix nav-flash on evil-multiedit or in eshell/term buffers + [X] ui/doom: fix nav-flash on evil-multiedit or in eshell/term buffers
+ [X] core-os: don't use GTK tooltips (ugly!) + [X] core-os: don't use GTK tooltips (ugly!)
+ [X] ui/doom-modeline: reduce excess whitespace on right of flycheck segment + [X] ui/doom-modeline: reduce excess whitespace on right of flycheck segment

View file

@ -1,22 +1,25 @@
;;; app/regex/autoload/regex.el ;;; app/regex/autoload/regex.el
(defvar +regex--text-buffer nil) (defvar +regex--text-buffer nil)
(defvar +regex--text-replace-buffer nil)
(defvar +regex--expr-buffer nil) (defvar +regex--expr-buffer nil)
(defvar +regex--expr-replace-buffer nil)
(defvar +regex--groups-buffer nil) (defvar +regex--groups-buffer nil)
(defvar +regex--replace-buffer nil)
;; ;;
(defface +regex-match-0-face (defface +regex-match-0-face
'((t (:foreground "Black" :background "Red" :bold t))) `((t (:foreground "Black" :background ,(doom-color 'magenta) :bold t)))
"TODO" "TODO"
:group 'doom) :group 'doom)
(defface +regex-match-1-face (defface +regex-match-1-face
'((t (:foreground "Black" :background "Blue" :bold t))) `((t (:foreground "Black" :background ,(doom-color 'blue) :bold t)))
"TODO" "TODO"
:group 'doom) :group 'doom)
(defface +regex-match-2-face (defface +regex-match-2-face
'((t (:foreground "Black" :background "Green" :bold t))) `((t (:foreground "Black" :background ,(doom-color 'green) :bold t)))
"TODO" "TODO"
:group 'doom) :group 'doom)
@ -27,9 +30,13 @@
;; ;;
(defvar +regex-mode-map (defvar +regex-mode-map
(let ((map (make-sparse-keymap))) (let ((map (make-sparse-keymap)))
(evil-define-key* 'normal map (define-key map "\C-c\C-c" #'+regex-update-buffers)
"\C-c\C-c" #'+regex-update-buffers (define-key map "\C-c\C-r" #'=regex/replace)
"\C-c\C-k" #'+regex/quit) (define-key map "\C-c\C-k" #'+regex/quit)
(define-key map [remap doom-kill-buffer] #'+regex/quit)
(define-key map [remap doom/kill-this-buffer] #'+regex/quit)
(define-key map [remap kill-this-buffer] #'+regex/quit)
(define-key map [remap kill-buffer] #'+regex/quit)
map) map)
"TODO") "TODO")
@ -48,6 +55,7 @@
(defun =regex (&optional dummy-text) (defun =regex (&optional dummy-text)
"Start the Regex IDE." "Start the Regex IDE."
(interactive "P") (interactive "P")
(unless (buffer-live-p +regex--expr-buffer)
(condition-case ex (condition-case ex
(progn (progn
(setq +regex--expr-buffer (get-buffer-create "*doom-regex*") (setq +regex--expr-buffer (get-buffer-create "*doom-regex*")
@ -56,67 +64,110 @@
(when dummy-text (when dummy-text
(+workspace-switch +regex-workspace-name t) (+workspace-switch +regex-workspace-name t)
(switch-to-buffer +regex--text-buffer) (switch-to-buffer +regex--text-buffer)
(insert +regex-dummy-text)) (with-current-buffer +regex--text-buffer
(insert +regex-dummy-text)))
(doom-popup-buffer +regex--groups-buffer) (doom-popup-buffer +regex--groups-buffer)
(doom-popup-buffer +regex--expr-buffer) (doom-popup-buffer +regex--expr-buffer)
(with-current-buffer +regex--expr-buffer (with-current-buffer +regex--expr-buffer
(conf-mode) (conf-mode)
(rainbow-delimiters-mode +1) (rainbow-delimiters-mode +1)
(linum-mode -1) (linum-mode -1)
(setq-local require-final-newline nil)
(+regex-mode +1) (+regex-mode +1)
(text-scale-set 3))) (text-scale-set 3)))
('error ('error
(+regex/quit) (+regex/quit)
(error "Failed to open the Regexp IDE: %s" ex)))) (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)
(linum-mode -1)
(setq-local require-final-newline nil)
(setq mode-line-format nil
+regex--expr-replace-buffer (current-buffer))
(+regex-mode +1)
(text-scale-set 3)))))
;;;###autoload ;;;###autoload
(defun +regex/quit () (defun +regex/quit ()
"TODO" "TODO"
(interactive) (interactive)
(kill-buffer +regex--expr-buffer)
(kill-buffer +regex--groups-buffer)
(when (and +regex--text-buffer (buffer-live-p +regex--text-buffer)) (when (and +regex--text-buffer (buffer-live-p +regex--text-buffer))
(with-current-buffer +regex--text-buffer (with-current-buffer +regex--text-buffer
(+regex-mode -1) (+regex-mode -1)
(remove-overlays))) (remove-overlays nil nil 'category '+regex))
(setq +regex--expr-buffer nil (when (equal (buffer-name +regex--text-buffer) "*doom-regex-text*")
+regex--text-buffer nil (kill-buffer +regex--text-buffer)))
+regex--groups-buffer nil)
(when (equal (+workspace-current-name) +regex-workspace-name) (when (equal (+workspace-current-name) +regex-workspace-name)
(kill-buffer +regex--text-buffer) (+workspace/delete +regex-workspace-name))
(+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)))))
;;;###autoload ;;;###autoload
(defun +regex-update-buffers (&optional beg end len) (defun +regex-update-buffers (&optional beg end len)
(interactive) (interactive)
(let ((regex (with-current-buffer +regex--expr-buffer (buffer-string)))) (let* ((inhibit-read-only t)
(when (> (length regex) 0) (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 (with-current-buffer +regex--groups-buffer
(erase-buffer)) (erase-buffer))
(with-current-buffer +regex--text-buffer (with-current-buffer +regex--text-buffer
(remove-overlays) (remove-overlays nil nil 'category '+regex)
(when (> (length regex) 0)
(save-excursion (save-excursion
(ignore-errors
(goto-char (point-min)) (goto-char (point-min))
(pcase +regex-default-backend (pcase +regex-default-backend
('emacs (+regex-backend-emacs regex)) ('emacs (+regex-backend-emacs regex replace str))
('perl (+regex-backend-generic (+regex-backend-perl regex))) ('perl (+regex-backend-perl regex replace str))))))
('python (+regex-backend-generic (+regex-backend-python regex)))))))
(with-current-buffer +regex--groups-buffer (with-current-buffer +regex--groups-buffer
(goto-char (point-min)))))) (goto-char (point-min)))))
;; --- backends --------------------------- ;; --- backends ---------------------------
(defun +regex--backend-perl (regex sample) (defun +regex--render-perl (regex text)
"From <https://github.com/jwiegley/regex-tool>" "From <https://github.com/jwiegley/regex-tool>"
(with-temp-buffer (with-temp-buffer
(unless (string-match-p "^/.+/[gm]*$" regex)
(setq regex (concat "/" regex "/g")))
(insert (format "@lines = <DATA>; (insert (format "@lines = <DATA>;
$line = join(\"\", @lines); $line = join(\"\", @lines);
print \"(\"; print \"(\";
while ($line =~ m%smg) { while ($line =~ m/%s/gm) {
print \"(\", length($`), \" \", length($&), \" \"; print \"(\", length($`), \" \", length($&), \" \";
for $i (1 .. 20) { for $i (1 .. 20) {
if ($$i) { if ($$i) {
@ -129,53 +180,95 @@ while ($line =~ m%smg) {
} }
print \")\"; print \")\";
__DATA__ __DATA__
%s" regex sample)) %s" (replace-regexp-in-string "/" "\\/" regex nil t) text))
(call-process-region (point-min) (point-max) "perl" t t) (call-process-region (point-min) (point-max) "perl" t t)
(goto-char (point-min)) (goto-char (point-min))
(read (current-buffer)))) (read (current-buffer))))
(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))))
;;;###autoload ;;;###autoload
(defun +regex-backend-perl (regex) (defun +regex-backend-perl (regex replace str)
"TODO" "TODO"
(let ((results (+regex--render-perl regex (buffer-string))) (cl-assert (stringp regex))
(i 0)) (cl-assert (stringp replace))
(dolist (result results) (cl-assert (stringp str))
(let ((offset (nth 0 result)) (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)) (length (nth 1 result))
(matches (nthcdr 2 result))) (matches (nthcdr 2 result))
(overlay-put (make-overlay (1+ offset) (+ offset length 1)) (ov (make-overlay (1+ offset) (+ offset length 1))))
'face (nth (mod i 3) +regex-faces)) (overlay-put ov 'face (nth (mod i 3) +regex-faces))
(overlay-put ov 'category '+regex)
(cl-incf i) (cl-incf i)
(let ((match-zero (buffer-substring (1+ offset) (+ offset length 1)))) (let* ((match-zero (buffer-substring (1+ offset) (+ offset length 1)))
(line (format "Match: %s\n" (propertize match-zero 'face 'font-lock-string-face))))
(with-current-buffer +regex--groups-buffer (with-current-buffer +regex--groups-buffer
(insert (format "Group 0: '%s'\n" match-zero)))) (insert line)))
(dolist (match matches) (dolist (match matches)
(with-current-buffer +regex--groups-buffer (with-current-buffer +regex--groups-buffer
(goto-char (point-max)) (goto-char (point-max))
(insert (format "Group %d: '%s'\n" (car match) (insert (format "Group %d: %s\n"
(cdr match))))) (propertize (car match) 'face 'font-lock-constant-face)
(propertize (cdr match) 'face 'font-lock-string-face)))))
(with-current-buffer +regex--groups-buffer (with-current-buffer +regex--groups-buffer
(insert ?\n)))))) (insert ?\n))))))
;;;###autoload ;;;###autoload
(defun +regex-backend-emacs (regex) (defun +regex-backend-emacs (regex replace str)
"TODO" "TODO"
(cl-assert (stringp regex))
(cl-assert (stringp replace))
(cl-assert (stringp str))
(let ((i 0) (let ((i 0)
pos) pos)
(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))))
(while (and (setq pos (point)) (while (and (setq pos (point))
(re-search-forward regex nil t)) (re-search-forward regex nil t))
(if (= (point) pos) (if (= (point) pos)
(forward-char 1) (forward-char 1)
(overlay-put (make-overlay (match-beginning 0) (let ((ov (make-overlay (match-beginning 0) (match-end 0))))
(match-end 0)) (overlay-put ov 'face (nth (mod i 3) +regex-faces))
'face (nth (mod i 3) +regex-faces)) (overlay-put ov 'category '+regex))
(cl-incf i) (cl-incf i)
(dotimes (i 10) (dotimes (i 10)
(when-let (text (match-string i)) (when-let (text (match-string i))
(save-match-data (save-match-data
(with-current-buffer +regex--groups-buffer (with-current-buffer +regex--groups-buffer
(goto-char (point-max)) (goto-char (point-max))
(insert (format "Group %d: '%s'\n" i text)))))) (insert
(format "Group %d: %s\n"
(propertize i 'face 'font-lock-constant-face)
(propertize text 'face 'font-lock-string-face)))))))
(with-current-buffer +regex--groups-buffer (with-current-buffer +regex--groups-buffer
(insert ?\n)))))) (insert ?\n))))))

View file

@ -47,6 +47,6 @@ https://mediatemple.net"
"TODO") "TODO")
(set! :popup (set! :popup
'("*doom-regex*" :size 4 :select t :noesc t :autokill t) '("*doom-regex*" :size 4 :select t :noesc t)
'("*doom-regex-groups*" :align left :size 30 :noselect t :noesc t :autokill t)) '("*doom-regex-groups*" :align left :size 30 :noselect t :noesc t))